- Accordion
- Avatar
- Badge
- Breadcrumb
- Button
- Calendar
- ChatContainer
- ChatInput
- ChatMessage
- ChatMultiChoiceQuestion
- ChatMultiOptionQuestion
- ChatThinking
- Checkbox
- Combobox
- Container
- CurrencyInput
- DistributionSlider
- Drawer
- Dropdown
- FilePicker
- Grid
- Heading
- Image
- Input
- InputGroup
- Label
- Logo
- MapPin
- Markdown
- Modal
- NativeSelect
- NumberInput
- OptionSlider
- OtpInput
- PhoneInput
- Popover
- Progress
- PropertyCalendar
- RadioGroup
- RadioGroupCards
- ResponsiveModal
- ScrollArea
- SearchBar
- SearchBarFallback
- SearchInput
- Select
- Separator
- Spinner
- Switch
- Table
- Tabs
- Text
- Textarea
- TimePicker
- Toast
- Toggle
- ToggleCard
- ToggleGroup
- Toolbar
- Tooltip
SearchBar
A compound search bar component for location, dates, and guests selection.
pnpm add @wandercom/design-system-web
The SearchBar is a compound component that provides a flexible search interface. It consists of a collapsed bar with location trigger, date/guest buttons, and an expandable dropdown panel for location search. By default it switches between mobile and desktop content from its own 65rem (1040px) query container. Pass inheritContainer when composing it inside an existing responsive container such as a Header.
import {
SearchBar,
SearchBarActionArea,
SearchBarButton,
SearchBarDesktop,
SearchBarLocationTrigger,
SearchBarRoot,
SearchBarSearchButton,
} from '@wandercom/design-system-web/ui/search-bar';
export function Example() {
return (
<SearchBarRoot
desktop={
<SearchBarDesktop>
<SearchBarLocationTrigger>Where</SearchBarLocationTrigger>
<SearchBarButton>Anytime</SearchBarButton>
<SearchBarActionArea>
<SearchBarButton>Any guests</SearchBarButton>
<SearchBarSearchButton />
</SearchBarActionArea>
</SearchBarDesktop>
}
/>
);
}Use SearchBar for the full experience with built-in panels and labels:
import { SearchBar } from '@wandercom/design-system-web/ui/search-bar';
export function Example() {
return (
<SearchBar
labels={{
searchLabel: 'Search',
locationLabel: 'Where',
}}
/>
);
}Use the location and onLocationChange props to manage location state externally, e.g. syncing with a map view.
import { SearchBar, type SearchBarLocation } from '@wandercom/design-system-web/ui/search-bar';
import { useState } from 'react';
export function ControlledLocationExample() {
const [location, setLocation] = useState<SearchBarLocation | null>(null);
return (
<SearchBar
location={location}
onLocationChange={setLocation}
onSearch={(values) => console.log(values)}
/>
);
}When location is omitted, the component manages its own state internally (uncontrolled mode, initialized from initialValues).
A complete search bar with curated empty-state content (recent searches and suggested regions) plus async-mode server search. Pass onLocationQueryChange to delegate filtering to the consumer (e.g. a remote search API) — the SearchBar debounces 200ms internally before invoking the callback. Combine with locationSuggestions, unitSuggestions, and isLoadingSuggestions to render results and loading state.
The loading label renders immediately on keystroke (no flash of "No results found" during the debounce window). If previous suggestions are visible when the user types again, the list dims with aria-busy + reduced opacity until new results arrive.
The SearchBarPopover provides a dropdown for location search with sections and items using the Popover component.
import {
SearchBarPopover,
SearchBarPopoverContent,
SearchBarPopoverInput,
SearchBarPopoverItem,
SearchBarPopoverSection,
SearchBarPopoverTrigger,
SearchBarLocationTrigger,
} from '@wandercom/design-system-web/ui/search-bar';
import { useState } from 'react';
export function LocationPopover() {
const [open, setOpen] = useState(false);
return (
<SearchBarPopover open={open} onOpenChange={setOpen}>
<SearchBarPopoverTrigger asChild>
<SearchBarLocationTrigger active={open}>Where</SearchBarLocationTrigger>
</SearchBarPopoverTrigger>
<SearchBarPopoverContent>
<SearchBarPopoverInput placeholder="Search locations..." />
<SearchBarPopoverSection label="Recent searches">
<SearchBarPopoverItem
title="Los Angeles"
subtitle="Los Angeles, California"
/>
<SearchBarPopoverItem
title="Joshua Tree"
subtitle="California, United States"
/>
</SearchBarPopoverSection>
</SearchBarPopoverContent>
</SearchBarPopover>
);
}Use the asChild prop to render custom elements while maintaining functionality.
import { SearchBarLocationTrigger } from '@wandercom/design-system-web/ui/search-bar';
import { Popover, PopoverTrigger } from '@wandercom/design-system-web/ui/popover';
export function ComposedTrigger() {
return (
<Popover>
<SearchBarLocationTrigger asChild>
<PopoverTrigger>Where</PopoverTrigger>
</SearchBarLocationTrigger>
</Popover>
);
}The SearchBarDatePopoverContent provides a date range picker with calendar, mode toggle (Dates/Flexible), and flexibility options. Click the "Anytime" button in the example above to see the date popover.
import {
SearchBarButton,
SearchBarDatePopoverCalendar,
SearchBarDatePopoverContent,
SearchBarDatePopoverDuration,
SearchBarDatePopoverFlexibility,
SearchBarDatePopoverHeader,
SearchBarDatePopoverMonthGrid,
SearchBarPopover,
SearchBarPopoverTrigger,
type SearchBarDateDuration,
type SearchBarDateMonth,
} from '@wandercom/design-system-web/ui/search-bar';
import { useState } from 'react';
import type { DateRange } from 'react-day-picker';
export function DatePopover() {
const [open, setOpen] = useState(false);
const [mode, setMode] = useState<'dates' | 'flexible'>('dates');
const [dateRange, setDateRange] = useState<DateRange | undefined>();
const [flexibility, setFlexibility] = useState<'exact' | '1' | '2' | '3' | '7'>('exact');
const [duration, setDuration] = useState<SearchBarDateDuration>('weekend');
const [selectedMonths, setSelectedMonths] = useState<SearchBarDateMonth[]>([]);
return (
<SearchBarPopover open={open} onOpenChange={setOpen}>
<SearchBarPopoverTrigger asChild>
<SearchBarButton>Anytime</SearchBarButton>
</SearchBarPopoverTrigger>
<SearchBarDatePopoverContent>
<SearchBarDatePopoverHeader
mode={mode}
onModeChange={setMode}
onClear={() => {
setDateRange(undefined);
setSelectedMonths([]);
}}
/>
{mode === 'dates' && (
<>
<SearchBarDatePopoverCalendar
selected={dateRange}
onSelect={setDateRange}
disabled={{ before: new Date() }}
/>
<SearchBarDatePopoverFlexibility
value={flexibility}
onValueChange={setFlexibility}
disabled={!dateRange?.from || !dateRange?.to}
/>
</>
)}
{mode === 'flexible' && (
<div className="flex flex-col gap-6 px-7 py-7">
<SearchBarDatePopoverDuration value={duration} onValueChange={setDuration} />
<SearchBarDatePopoverMonthGrid selected={selectedMonths} onSelect={setSelectedMonths} />
</div>
)}
</SearchBarDatePopoverContent>
</SearchBarPopover>
);
}The SearchBarGuestsPopoverContent provides a stepper interface for selecting guests and pets. Click the "Who" button in the example above to see the guests popover.
import {
SearchBarButton,
SearchBarGuestsPopoverContent,
SearchBarGuestsPopoverRow,
SearchBarPopover,
SearchBarPopoverTrigger,
} from '@wandercom/design-system-web/ui/search-bar';
import { useState } from 'react';
export function GuestsPopover() {
const [open, setOpen] = useState(false);
const [guests, setGuests] = useState(1);
const [pets, setPets] = useState(0);
return (
<SearchBarPopover open={open} onOpenChange={setOpen}>
<SearchBarPopoverTrigger asChild>
<SearchBarButton>Any guests</SearchBarButton>
</SearchBarPopoverTrigger>
<SearchBarGuestsPopoverContent>
<SearchBarGuestsPopoverRow
label="Guests"
value={guests}
onChange={setGuests}
min={1}
max={16}
/>
<SearchBarGuestsPopoverRow
label="Pets"
value={pets}
onChange={setPets}
max={10}
/>
</SearchBarGuestsPopoverContent>
</SearchBarPopover>
);
}className?:
locations?:
units?:
recentSearches?:
suggestedRegions?:
initialValues?:
minDate?:
labels?:
onSearch?:
location?:
onLocationChange?:
onLocationSelect?:
onLocationQueryChange?:
locationSuggestions?:
unitSuggestions?:
isLoadingSuggestions?:
filtersContent?:
filtersValue?:
onClearFilters?:
desktopFiltersContent?:
asChild?:
inheritContainer?:
onLayoutChange?:
className?:
desktop?:
mobile?:
asChild?:
inheritContainer?:
onLayoutChange?:
children?:
className?:
children:
activeSegment?:
onActiveSegmentChange?:
hasLocationValue?:
hasDatesValue?:
hasGuestsValue?:
active?:
asChild?:
className?:
label?:
placeholder?:
asChild?:
active?:
segment?:
className?:
label?:
placeholder?:
className?:
children:
className?:
children?:
Re-exported Radix Popover component for controlling open/closed state.
Re-exported PopoverTrigger for triggering the popover. Use with asChild prop.
Re-exported PopoverAnchor for custom anchor positioning.
Extends all PopoverContent props from Radix.
className?:
children:
align?:
sideOffset?:
placeholder?:
className?:
onClear?:
onSubmit?:
label?:
maxItems?:
className?:
children:
title:
subtitle?:
icon?:
image?:
selected?:
asChild?:
onSelect?:
navigateTo?:
className?:
Extends all PopoverContent props from Radix.
className?:
children:
align?:
sideOffset?:
mode?:
onModeChange?:
onClear?:
showClear?:
className?:
datesLabel?:
flexibleLabel?:
clearLabel?:
Extends most DayPickerProps from react-day-picker (excluding mode, numberOfMonths, and showOutsideDays).
selected?:
onSelect?:
endMonth?:
disabled?:
className?:
value?:
onValueChange?:
disabled?:
className?:
exactLabel?:
oneDayLabel?:
twoDaysLabel?:
threeDaysLabel?:
sevenDaysLabel?:
value?:
onValueChange?:
className?:
titleLabel?:
weekendLabel?:
weekLabel?:
selected?:
onSelect?:
monthCount?:
startDate?:
titleLabel?:
className?:
Extends all PopoverContent props from Radix.
className?:
children:
align?:
sideOffset?:
label:
value:
onChange:
min?:
max?:
className?:
className?:
children?:
open?:
onOpenChange?:
trigger?:
activeSegment?:
onActiveSegmentChange?:
hasLocationValue?:
hasDatesValue?:
hasGuestsValue?:
onSearch?:
footer?:
titleLabel?:
filtersLabel?:
filtersPlaceholder?:
filtersValue?:
filtersContent?:
onClearFilters?:
filtersTitleLabel?:
clearFiltersLabel?:
clearSearchLabel?:
closeSearchLabel?:
closeFiltersLabel?:
showResultsLabel?:
loadingSuggestionsLabel?:
unsetValuePlaceholder?:
className?:
onSkip?:
showSkip?:
searchLabel?:
nextLabel?:
skipLabel?:
className?:
placeholder?:
location?:
dates?:
guests?:
section?:
label:
value?:
expanded?:
onClick?:
headerAction?:
autoFocus?:
className?:
children?:
className?:
children?:
A self-contained calendar experience for the mobile drawer, including a mode toggle (Dates/Flexible), date range calendar with day-of-week labels, flexibility selector, duration toggle, and month grid.
selected?:
onSelect?:
mode?:
onModeChange?:
flexibility?:
onFlexibilityChange?:
numberOfMonths?:
minDate?:
duration?:
onDurationChange?:
selectedMonths?:
onSelectedMonthsChange?:
labels?:
className?:
A lightweight static fallback for use with Suspense boundaries or initial server renders. See the SearchBar Fallback documentation for full details.
The SearchBar component includes proper accessibility features:
- Uses semantic button elements for interactive triggers
- Dividers are marked with
aria-hidden="true" - Panel items support
aria-selectedfor selection state - All interactive elements are keyboard accessible
- Focus states are visible with proper styling
- Screen reader compatible with proper text labels
- Stepper buttons have descriptive
aria-labelattributes (e.g., "Increase guests", "Decrease pets") - Counter values use
aria-live="polite"to announce changes to screen readers - Disabled buttons are properly marked with
disabledattribute