primaryAction?:
{ label: string; action: () => void }
Primary footer action (e.g., "Show 24 results").
Composable filter sections for search interfaces with price distribution, amenities, rooms, and property type sections. Available as SearchFiltersContent (headless) and SearchFiltersModal (with ResponsiveModal wrapper).
pnpm add @wandercom/design-system-web
import { SearchFiltersModal } from '@wandercom/design-system-web/blocks/search-filters';
import { Button } from '@wandercom/design-system-web/ui/button';
export function Example() {
const [priceRange, setPriceRange] = useState<[number, number]>([100, 800]);
const [amenities, setAmenities] = useState<string[]>([]);
const [bedrooms, setBedrooms] = useState<number | null>(null);
const [bathrooms, setBathrooms] = useState<number | null>(null);
const [propertyTypes, setPropertyTypes] = useState<string[]>([]);
return (
<SearchFiltersModal
trigger={<Button variant="outline">Filters</Button>}
price={{
data: priceDistribution,
value: priceRange,
onChange: setPriceRange,
min: 0,
max: 1000,
currency: "$",
}}
amenities={{
options: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "pool", label: "Pool" },
{ key: "hot-tub", label: "Hot Tub" },
],
value: amenities,
onChange: setAmenities,
}}
rooms={{
bedrooms,
bathrooms,
onBedroomsChange: setBedrooms,
onBathroomsChange: setBathrooms,
}}
propertyTypes={{
options: [
{ key: "house", label: "House" },
{ key: "apartment", label: "Apartment" },
{ key: "cabin", label: "Cabin" },
],
value: propertyTypes,
onChange: setPropertyTypes,
}}
primaryAction={{ label: "Show results", action: () => undefined }}
secondaryAction={{ label: "Clear all", action: () => undefined }}
/>
);
}All filter sections are optional. Only sections with provided configuration are rendered, separated by dividers. State is fully managed by the consumer.
Each filter section accepts an optional label prop to override the default heading.
<SearchFiltersModal
trigger={<Button variant="outline">Filters</Button>}
price={{ ...priceConfig, label: "Nightly rate" }}
amenities={{ ...amenitiesConfig, label: "Must-haves" }}
rooms={{ ...roomsConfig, label: "Sleeping arrangements" }}
propertyTypes={{ ...propertyTypesConfig, label: "Stay type" }}
/>Use children to add custom filter sections below the built-in ones.
<SearchFiltersModal
trigger={<Button variant="outline">Filters</Button>}
price={priceConfig}
>
<div className="flex flex-col gap-2">
<span className="font-semibold text-body-sm">Rating</span>
{/* custom rating filter UI */}
</div>
</SearchFiltersModal>Use getSearchFiltersLabel to derive a summary string from filter state for the SearchBar's filtersValue prop. Returns undefined when no filters are active, falling through to the default placeholder.
import { SearchFiltersContent, SearchFiltersModal, getSearchFiltersLabel } from '@wandercom/design-system-web/blocks/search-filters';
<SearchBar
filtersValue={getSearchFiltersLabel({
amenities,
bedrooms,
bathrooms,
propertyTypes,
priceRange,
priceMin: 0,
priceMax: 1000,
})}
filtersContent={
<SearchFiltersContent
price={priceConfig}
amenities={amenitiesConfig}
rooms={roomsConfig}
propertyTypes={propertyTypesConfig}
/>
}
desktopFiltersContent={
<SearchFiltersModal
trigger={<Button variant="outline">Filters</Button>}
price={priceConfig}
amenities={amenitiesConfig}
rooms={roomsConfig}
propertyTypes={propertyTypesConfig}
primaryAction={{ label: "Show results", action: handleApply }}
secondaryAction={{ label: "Clear all", action: handleClear }}
/>
}
/>