Components
Search Bar
StableThe SearchBar is a three-field holiday search widget — destination, departure date and traveller count — used at the top of search and results pages.
Travellers
Purpose
The SearchBar is the primary entry point for holiday discovery. It collects the three key parameters a Kuoni search requires — where, when, and how many — and submits them via the onSearch callback. The consuming page or route handles navigation to search results.
It appears:
- In the homepage hero section (the most prominent placement)
- At the top of the /offers/ listing page
- Potentially stickied above search results on scroll
The SearchBar is a client component with internal state for field values and the traveller picker dropdown. Pass defaultDestination, defaultDate, defaultAdults, and defaultChildren to pre-fill it for returning users or for contextual placements (e.g. pre-fill "Maldives" on the Maldives destination page).
Usage
Reach for SearchBar as the entry point into holiday discovery — it's for starting a new search, not for narrowing results already on screen. Once a user has landed on a results page, use Quick Filter Bar to refine results and Sort Dropdown to reorder them; SearchBar itself is not meant to be repeated as an in-page filter control.
It appears once per page, in the highest-prominence position: the homepage hero, the top of the /offers/ listing page, and optionally stickied above results on scroll.
Anatomy
Travellers
- 1Container — White rounded-xl card with shadow and border. Flex row on desktop (≥768px), stacked column on mobile.
- 2Destination panel — MapPin icon + "Destination" label + free-text input. Placeholder: "Where would you like to go?"
- 3Date panel — Calendar icon + "Departure date" label + native date input. Shows the browser date picker on focus.
- 4Travellers panel — Users icon + "Travellers" label + button showing current count. Clicking opens the traveller picker dropdown.
- 5Traveller picker — Absolute-positioned dropdown with Adults and Children counters (− N +). Closes on outside click or Escape.
- 6Search button — Teal button, full height on the right. Calls the onSearch callback with current field values.
Variants
Default — three panels
Destination, departure date, and travellers. Use this for all primary search placements.
Travellers
Pre-filled for context
Pre-fill the destination when the search bar appears on a destination page. The user still sees the value and can modify it.
Travellers
States
Idle
All fields show their placeholder text or default values. The traveller picker is closed.
Destination focused
The destination text input has browser focus. The cursor appears. The field label is always visible — it does not collapse into the placeholder on focus.
Traveller picker open
Clicking the Travellers panel toggles the picker dropdown. The dropdown shows Adults (min 1) and Children (min 0, under 18) counters with − and + buttons. A "Done" button closes the picker.
The picker closes on:
- Clicking "Done"
- Clicking outside the travellers panel and picker
- Pressing Escape
Filled
All fields have values. The summary line in the Travellers panel updates to reflect the count: "2 Adults" → "2 Adults, 1 Child".
Mobile layout
On screens below 768px (md breakpoint), the three panels stack vertically with a border between each. The Search button spans the full width at the bottom.
Travellers
Best practices
Pre-fill defaultDestination with the current region when the SearchBar appears on a destination page.
Pre-filled destination creates a faster path to results on destination pages.
Clear the destination field when navigating between pages if the user already filled it.
Resetting all fields on every page mount ignores the user's stated intent.
Pass an onSearch handler that navigates to your results route with the search parameters.
The onSearch callback receives all field values — use them to build the query URL.
Render SearchBar without an onSearch prop in a production placement.
Without an onSearch handler the Search button silently does nothing.
Use the native date input for date selection unless your design system requires a custom calendar picker.
The native date input is accessible and familiar — prefer it over a custom calendar.
Hide the date and travellers panels to save space — use a compact text input instead.
Showing only the destination field removes the context a traveller needs to search meaningfully.
Let the traveller summary label update reactively as the user adjusts counts.
'1 Adult, 2 Children' in the travellers summary is more informative than a number alone.
Show only a number in the travellers field without the 'Adults' / 'Children' labels.
A count of '3' without context is ambiguous — is it adults, or total people?
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultDestination | string | '' | Initial value for the destination text field. Shown on mount; user can edit. |
| defaultDate | string | '' | Initial value for the date field in ISO format (YYYY-MM-DD). |
| defaultAdults | number | 2 | Initial adult count. Minimum 1, maximum 9. |
| defaultChildren | number | 0 | Initial children count (under 18). Minimum 0, maximum 9. |
| onSearch | ({ destination, date, adults, children }: SearchParams) => void | — | Called when the Search button is clicked. Receives all current field values. Use to navigate to results. |
| className | string | — | Additional Tailwind classes on the root container element. |
Accessibility
Form landmark
The root element has role="search" and aria-label="Holiday search". This exposes it as a search landmark in the accessibility tree — screen reader users can jump directly to it using landmark navigation.
Field labels
Each panel has a visible label (not a floating placeholder). Labels are associated with their inputs:
- Destination:
<label htmlFor="sb-destination"> - Departure date:
<label htmlFor="sb-date"> - Travellers: a
<p>label with the Travellers button below
This means a screen reader user hears "Destination — text input" and "Departure date — date input" without needing to guess from placeholder text alone.
Traveller picker
The Travellers toggle button has:
aria-expanded={travellersOpen}— announces open/closed statearia-haspopup="dialog"— signals a popup will appear
Each counter button has an aria-label like "Increase Adults count" and "Decrease Children count". The count value has aria-live="polite" so screen readers announce it when it changes.
Keyboard interaction
| Key | Action |
|---|---|
Tab | Move between destination, date, travellers button, search button |
Enter / Space | Open travellers picker (when travellers button focused) |
Escape | Close travellers picker |
Tab within picker | Move between − and + buttons and Done button |
Search button
The Search button has aria-label="Search holidays" in addition to the visible "Search" label, so the icon is not the sole accessible name.
Related components
- Quick Filter Bar — refines results already returned by a search; used together with SearchBar in a typical search-to-results flow.
- Sort Dropdown — reorders results after a search; commonly sits alongside the results grid that SearchBar's query populates.