Quire UI
Controls10

Select

Pick one option from a list, with the chosen item opening right over the trigger.

Installation

npx shadcn@latest add @quireui/select

Usage

const roles = [
  { value: "admin", label: "Admin" },
  { value: "member", label: "Member" },
];

<Select items={roles} defaultValue="member">
  <SelectTrigger>
    <SelectValue />
  </SelectTrigger>
  <SelectContent>
    {roles.map((r) => (
      <SelectItem key={r.value} value={r.value}>
        {r.label}
      </SelectItem>
    ))}
  </SelectContent>
</Select>

Pass items to Select so the trigger shows the label, not the raw value. It is the same list you render, so there is nothing extra to keep in sync.

Groups and long lists

Group options with SelectGroup and a SelectLabel, and divide groups with SelectSeparator. Anything after the label text in an item, like the offset below, sits on the right.

The open list places the chosen item right over the trigger, so the eye never has to jump. When the list is longer than the space around it, arrows appear at the top and bottom; hovering them scrolls. Pass alignItemWithTrigger={false} to open below the trigger instead.

In a form

Inside a Field with a name, the value is submitted with the form and required is validated like Input: the error appears under the field without moving anything below it.

You can change it any time.

<Form onFormSubmit={(values) => save(values.plan)}>
  <Field name="plan">
    <FieldLabel>Plan</FieldLabel>
    <Select items={plans} required>
      <SelectTrigger>
        <SelectValue placeholder="Choose a plan" />
      </SelectTrigger>
      <SelectContent>{/* items */}</SelectContent>
    </Select>
    <FieldError />
  </Field>
</Form>

Sizes

size on Select: sm, md (default) or lg, the same heights as Button and Input, so a select sits flush in a toolbar or a form row. The open list follows the size too, so it still covers the trigger exactly. All three follow the density.

Accessibility

The trigger is read with its label and the chosen value. The list is a listbox, and the highlighted option is read as you move.

KeyAction
Space / ↓ / ↑On the trigger: opens the list with the chosen item highlighted.
LettersOn the closed trigger: picks the next option starting with that letter, without opening. In the open list: jumps the highlight there.
↓ / ↑Moves the highlight.
Home / EndJumps to the first or last option.
Enter / SpacePicks the highlighted option and closes.
EscCloses without changing the value.
TabCloses and moves on, keeping the value.

Enter does not open a closed select, the same as a native one, so pressing Enter in a form never opens a list by surprise.

Select or something else?

  • Many options, or people search by name: Combobox filters as you type.
  • Two to four options that should all stay visible: radio group or a segmented toggle group.
  • Actions rather than a value: Dropdown menu.

API reference

Select

Prop

Type

Also takes every prop of Base UI's Select.Root.

SelectGroup

Also takes every prop of Base UI's Select.Group.

SelectTrigger

Also takes every prop of Base UI's Select.Trigger. Style it with [data-slot="select"].

SelectValue

The chosen item's label, or placeholder in a quieter colour until something is picked.

Also takes every prop of Base UI's Select.Value.

SelectContent

Also takes every prop of Base UI's Select.Popup. Style it with [data-slot="select-content"].

SelectItem

Also takes every prop of Base UI's Select.Item.

SelectLabel

Also takes every prop of Base UI's Select.GroupLabel.

SelectSeparator

Also takes every prop of Base UI's Select.Separator.

On this page