Wuko
Components

Select

A dropdown menu of options triggered by a button. Built on Radix Select for full keyboard navigation, search-as-you-type, and accessibility. The trigger styling matches Input so Select fits cleanly into form layouts.

Installation

terminal
npx shadcn@latest add @wuko/select

Usage

components/example.tsx
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";

export function Example() {
  return (
    <Select>
      <SelectTrigger className="w-45">
        <SelectValue placeholder="Select a fruit" />
      </SelectTrigger>
      <SelectContent>
        <SelectItem value="apple">Apple</SelectItem>
        <SelectItem value="banana">Banana</SelectItem>
        <SelectItem value="blueberry">Blueberry</SelectItem>
      </SelectContent>
    </Select>
  );
}

Composition

Use the following composition to build a Select.

text
Select
├── SelectTrigger
│   └── SelectValue
└── SelectContent
    ├── SelectGroup
    │   ├── SelectLabel
    │   ├── SelectItem
    │   └── SelectItem
    ├── SelectSeparator
    └── SelectGroup
        ├── SelectLabel
        ├── SelectItem
        └── SelectItem

Groups

Use SelectGroup, SelectLabel, and SelectSeparator to organize related items into sections.

tsx
<Select>
  <SelectTrigger className="w-50">
    <SelectValue placeholder="Select a fruit" />
  </SelectTrigger>
  <SelectContent>
    <SelectGroup>
      <SelectLabel>Citrus</SelectLabel>
      <SelectItem value="orange">Orange</SelectItem>
      <SelectItem value="lemon">Lemon</SelectItem>
    </SelectGroup>
    <SelectSeparator />
    <SelectGroup>
      <SelectLabel>Berries</SelectLabel>
      <SelectItem value="strawberry">Strawberry</SelectItem>
      <SelectItem value="blueberry">Blueberry</SelectItem>
    </SelectGroup>
  </SelectContent>
</Select>

Scrollable

When the content exceeds the popover height, scroll buttons appear at the top and bottom for keyboard and mouse users.

tsx
<Select>
  <SelectTrigger className="w-55">
    <SelectValue placeholder="Select a timezone" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="utc-8">(UTC-08:00) Pacific Time</SelectItem>
    <SelectItem value="utc-5">(UTC-05:00) Eastern Time</SelectItem>
    <SelectItem value="utc-0">(UTC+00:00) UTC</SelectItem>
    <SelectItem value="utc+1">(UTC+01:00) Berlin</SelectItem>
    {/* ...more items */}
  </SelectContent>
</Select>

Disabled

Set disabled on the root Select to disable the whole control, or disabled on a single SelectItem to disable just that option.

tsx
<Select disabled>
  <SelectTrigger className="w-45">
    <SelectValue placeholder="Select a fruit" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="apple">Apple</SelectItem>
  </SelectContent>
</Select>

Invalid

Set aria-invalid="true" on the SelectTrigger to show an error state. The border and focus ring turn red.

tsx
<Select>
  <SelectTrigger aria-invalid="true" className="w-45">
    <SelectValue placeholder="Select a fruit" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="apple">Apple</SelectItem>
  </SelectContent>
</Select>

Sub-components

Each sub-component forwards className and all native props for its underlying Radix primitive.

PropTypeDefaultDescription
SelectRadix RootThe root container. Controlled via value/onValueChange or uncontrolled via defaultValue.
SelectTriggerRadix TriggerThe button that opens the menu. Styled like an Input. Accepts aria-invalid for error states.
SelectValueRadix ValueDisplays the selected value (or placeholder) inside the trigger.
SelectContentRadix Contentposition="popper"The floating panel. Renders into a portal. Position prop: "popper" (aligns to trigger edge) or "item-aligned" (positions selected item over trigger).
SelectItemRadix ItemA selectable option. Requires a value prop. Supports disabled.
SelectGroupRadix GroupWraps related items. Pair with SelectLabel for a section heading.
SelectLabelRadix LabelA non-selectable heading for a SelectGroup.
SelectSeparatorRadix SeparatorA thin divider between SelectGroups.

Accessibility

  • Built on Radix Select. Full keyboard support: Enter or Space opens, Arrow keys move between items, Esc closes, Home/End jump to first and last items, type-to-search jumps to the first matching item.
  • The trigger automatically links to the content via aria-controls and aria-expanded. Screen readers announce the menu state and selected value.
  • For invalid state, set aria-invalid="true" on SelectTrigger. The visual change is paired with the ARIA attribute so screen readers announce the error.
  • SelectGroup + SelectLabel creates a labeled section announced by screen readers (similar to <optgroup> in native select).
  • For form submission, pass name on the root Select. Radix renders a hidden native select for form compatibility.