Select
A dropdown selection component that allows users to choose a single option from a list
pnpm add @wandercom/design-system-web
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectSeparator,
SelectTrigger,
SelectValue,
} from '@wandercom/design-system-web/ui/select';
export function Example() {
return (
<Select>
<SelectTrigger>
<SelectValue placeholder="Select an option" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option-1">Option 1</SelectItem>
<SelectItem value="option-2">Option 2</SelectItem>
<SelectItem value="option-3">Option 3</SelectItem>
</SelectContent>
</Select>
);
}The default example shows both size variants (default and sm), the disabled state, and the invalid state using aria-invalid.
<Select>
<SelectTrigger className="w-[200px]">
<SelectValue placeholder="Choose an option" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">Option 1</SelectItem>
<SelectItem value="2">Option 2</SelectItem>
<SelectItem value="3">Option 3</SelectItem>
</SelectContent>
</Select>
<Select>
<SelectTrigger size="sm" className="w-[200px]">
<SelectValue placeholder="Small select" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">Option 1</SelectItem>
<SelectItem value="2">Option 2</SelectItem>
<SelectItem value="3">Option 3</SelectItem>
</SelectContent>
</Select>
<Select disabled>
<SelectTrigger className="w-[200px]">
<SelectValue placeholder="Disabled select" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">Option 1</SelectItem>
<SelectItem value="2">Option 2</SelectItem>
<SelectItem value="3">Option 3</SelectItem>
</SelectContent>
</Select>
<Select defaultValue="invalid">
<SelectTrigger aria-invalid="true" className="w-[200px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="invalid">Invalid selection</SelectItem>
<SelectItem value="1">Option 1</SelectItem>
<SelectItem value="2">Option 2</SelectItem>
<SelectItem value="3">Option 3</SelectItem>
</SelectContent>
</Select>Use SelectGroup, SelectLabel, and SelectSeparator to organize options into labeled sections.
<Select>
<SelectTrigger className="w-[200px]">
<SelectValue placeholder="Choose a city" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>East Coast</SelectLabel>
<SelectItem value="nyc">New York</SelectItem>
<SelectItem value="bos">Boston</SelectItem>
<SelectItem value="dc">Washington DC</SelectItem>
</SelectGroup>
<SelectSeparator />
<SelectGroup>
<SelectLabel>West Coast</SelectLabel>
<SelectItem value="sf">San Francisco</SelectItem>
<SelectItem value="la">Los Angeles</SelectItem>
<SelectItem value="sea">Seattle</SelectItem>
</SelectGroup>
</SelectContent>
</Select>The popup is capped at 500px tall by default. When the options overflow, the list scrolls and chevron indicators appear over the top and bottom edges to show more content is available; hovering an indicator scrolls the list. Set scrollable={false} on SelectContent to let the popup grow to the full available height without indicators.
<Select>
<SelectTrigger className="w-[280px]">
<SelectValue placeholder="Choose a timezone" />
</SelectTrigger>
<SelectContent>
{timezones.map(({ value, label }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
<Select>
<SelectTrigger className="w-[280px]">
<SelectValue placeholder="Choose a timezone" />
</SelectTrigger>
<SelectContent scrollable={false}>
{timezones.map(({ value, label }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>By default an item grows so long labels wrap onto multiple lines. Pass truncate on SelectItem to pin the row to a single line and ellipsize overflowing text instead. Truncation is intended for plain text labels; keep the default growing behavior for labels that include icons or other elements.
<Select>
<SelectTrigger className="w-[280px]">
<SelectValue placeholder="Choose a timezone" />
</SelectTrigger>
<SelectContent>
{timezones.map(({ value, label }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
<Select>
<SelectTrigger className="w-[280px]">
<SelectValue placeholder="Choose a timezone" />
</SelectTrigger>
<SelectContent>
{timezones.map(({ value, label }) => (
<SelectItem key={value} truncate value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>defaultValue?:
value?:
onValueChange?:
items?:
disabled?:
required?:
name?:
open?:
onOpenChange?:
size?:
className?:
scrollable?:
side?:
sideOffset?:
align?:
alignOffset?:
alignItemWithTrigger?:
position?:
container?:
className?:
value:
truncate?:
disabled?:
className?:
className?:
placeholder?:
className?:
The Select component is built on the Base UI Select primitive, which provides full WAI-ARIA compliance out of the box.
- Renders with
role="combobox"on the trigger androle="listbox"on the content, following the WAI-ARIA listbox pattern - Supports keyboard interaction:
SpaceandEnteropen the dropdown, arrow keys navigate options, andEscapecloses it - Type-ahead support allows users to jump to options by typing characters
- Focus is indicated with a visible border for keyboard navigation
- Disabled selects apply
aria-disabledand reduce interactivity to communicate their state visually - Set
aria-invalid="true"on the trigger to indicate validation errors with a destructive border style