KKUONIDesign System

Components

Sort Dropdown

Beta

A compact single-select dropdown for sorting search results. Shows the active sort label in a small trigger button. Used above resort and holiday listing grids.

Purpose

The SortDropdown changes the ordering of a results list without opening a full filter panel. It occupies minimal vertical space — the trigger is only 32 px tall — and sits at the top-right of a results grid alongside the result count.

Common sort orders on a travel site:

  • Most popular — editorial or algorithmic default
  • Price: low to high — budget-conscious user
  • Price: high to low — luxury-seeking user
  • Star rating — accommodation quality sort
  • Duration — shortest to longest trip

Only one sort option is active at a time. The active option is shown in the trigger button and marked with a Check icon inside the panel.

Usage

Reach for SortDropdown specifically to reorder an existing results list — not to filter it. When travellers need to narrow results by criteria (price range, star rating, board basis), use Quick Filter Bar instead; the two typically appear together above the same grid, with sort on one side and filters on the other. For a general single-select form field outside a results context, use Select.

SortDropdown sits at the top-right of a results grid — resort listings, holiday search results — aligned with the result count.

Anatomy

  1. 1
    Trigger buttonCompact h-8 button showing "Sort: {activeLabel}". ChevronDown icon rotates 180° when open.
  2. 2
    Dropdown panelPositioned below the trigger. white bg, border-grey-200 border, shadow-kuoni-lg. z-dropdown.
  3. 3
    Option row14 px text. Active row has text-teal and a Check icon on the right.
  4. 4
    Check iconCheck from lucide-react. Visible only on the currently selected option.

Variants

Default options

The built-in options cover the standard travel sort taxonomy. Use without any props to get the full set.


Custom options

Override with options when the context requires different sort criteria.


Controlled

Use value + onChange to sync the sort selection with parent state or URL params.

States

ElementStateAppearance
TriggerClosedGrey border, grey-700 text, chevron down
TriggerOpenTeal border, teal text, chevron up
TriggerHoverTeal border, teal text
TriggerFocusTeal focus ring
OptionDefaultGrey-700 text, no icon
OptionActiveTeal text, Check icon on right
OptionHoverGrey-50 background
PanelOpenshadow-kuoni-lg, z-dropdown, min-w full

Best practices

Do

Always show the active sort label in the trigger so users can see the current ordering at a glance.

'Sort: Most popular' in the trigger immediately tells users the current ordering without opening the panel.

Don't

Use a generic 'Sort' or 'Order by' label that does not reflect the current selection.

A trigger labelled only 'Sort ▾' gives no indication of the current order — the user must open the panel to find out.

Do

Label sort options with their effect, not a generic direction ('ascending', 'descending').

'Price: low to high' and 'Price: high to low' are clear — users know which direction they'll get.

Don't

Use abstract direction terms like 'ascending' or 'A → Z' without specifying what is being sorted.

'Ascending' and 'Descending' are ambiguous — ascending price? ascending alphabetically?

Do

Position the trigger near the results it controls so the spatial relationship is clear.

Place the SortDropdown at the top-right of the results grid, aligned with the result count on the left.

Don't

Place the SortDropdown below the results list or far from the grid it controls.

A sort control at the bottom of a 48-card results grid requires users to scroll past all results to change the order.

Props

PropTypeDefaultDescription
optionsArray<{ value: string; label: string }>built-in 5 optionsSort options. Defaults to: Most popular, Price low to high, Price high to low, Star rating, Duration.
defaultValuestringfirst option valueInitially selected value for uncontrolled usage.
valuestringControlled selected value. Combine with onChange to sync with URL params or parent state.
onChange(value: string) => voidCalled with the selected option value when the user picks a new sort.
classNamestringAdditional Tailwind classes on the root container.

Accessibility

ARIA listbox pattern

The panel uses role="listbox" with aria-label="Sort results by". Each option uses role="option" and aria-selected:

<div role="listbox" aria-label="Sort results by">
  <div role="option" aria-selected={false}>Most popular</div>
  <div role="option" aria-selected={true}>Price: low to high</div>
</div>

The trigger has aria-haspopup="listbox" and aria-expanded so assistive technology announces it as a listbox trigger.

Keyboard interaction

KeyAction
Enter / SpaceOpen or close the dropdown
EscapeClose the dropdown without changing selection
TabMove focus through options when open
Enter / Space on optionSelect the focused option and close
Click outsideClose the dropdown
  • Select — the general-purpose single-select dropdown; SortDropdown is a compact, purpose-built variant of the same pattern for result ordering.
  • Quick Filter Bar — narrows results by criteria; commonly paired with SortDropdown above the same results grid.