videorc/ui

Select

Choose one value from a list. A 28 px trigger (24 px in dense rows) and a list on the popup tier of the float glass; inside a Field, its label names it.

Installation

$ pnpm dlx shadcn@latest add @videorc/select

Usage

import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
const frameRates = [
  { label: "30 fps", value: "30" },
  { label: "60 fps", value: "60" },
];

<Select defaultValue="60" items={frameRates}>
  <SelectTrigger aria-label="Frame rate">
    <SelectValue />
  </SelectTrigger>
  <SelectContent>
    <SelectGroup>
      {frameRates.map((rate) => (
        <SelectItem key={rate.value} value={rate.value}>
          {rate.label}
        </SelectItem>
      ))}
    </SelectGroup>
  </SelectContent>
</Select>;

Pass items to the root so the trigger shows the chosen item's label rather than its raw value. Put items in a SelectGroup: the group brings the 4 px inset the items sit in.

Anatomy

<Select>
  <SelectTrigger>
    <SelectValue />
  </SelectTrigger>
  <SelectContent>
    <SelectGroup>
      <SelectLabel />
      <SelectItem />
    </SelectGroup>
    <SelectSeparator />
  </SelectContent>
</Select>

Examples

Placeholder

The placeholder is an item with a null value in items. Leave it out of the list when it can't be chosen back.

Groups

Label groups of like things with SelectLabel, and split them with a SelectSeparator inside the next group. With alignItemWithTrigger={false} the list opens under the trigger instead of over it.

Sizes

xs (24 px) is for dense rows only: a row's trailing control, a card's actions, the Stream Manager's panes. A page's or a dialog's selects stay 28 px.

Theming

Token or attributeMeaning
bg-input/50, rounded-chipThe trigger's fill and 6 px corners
h-controlThe 28 px trigger, by data-size="default"; xs is 24 px
data-placeholderOn the trigger while nothing is chosen: muted text
glass-float, rounded-lgThe popup tier and its 10 px corners
min-h-7, rounded-chip28 px items with 6 px corners
data-align-triggerThe list opens over the trigger, unanimated
overscroll-containA long list's scroll doesn't chain to the page

selectTriggerClassName is the trigger's look on its own, for a button that opens a popover but must look exactly like a select.

Keyboard

KeyAction
Enter, Space, ArrowDown, ArrowUpOn the trigger, opens the list
ArrowDown, ArrowUpMoves between items
Home, EndMoves to the first or last item
A letterMoves to the next item that starts with it
Enter, SpaceChooses the highlighted item
EscapeCloses the list without choosing

Accessibility

Every trigger has a name. Inside a Field the FieldLabel names it and the FieldDescription describes it, with no ids to wire; outside one, give the trigger an aria-label. The list stops wheel events at its edge, so a fader or a scrolling pane behind it doesn't move.

API reference

Every Base UI Select prop, plus:

SelectTrigger

Prop

Type

SelectContent

Prop

Type