Select
A field to pick one option, or several, from a list, with Input Field's label and states, and search when the list is long. Use it for 5 or more options; for fewer, radio buttons or checkboxes.
Preview
Mirrored is the same English content laid out right to left: it separates a mirroring bug from a translation one.
Installation
npx shadcn@latest add @ritla/selectDependencies it brings: @base-ui/react, @phosphor-icons/react
Usage
import { Select } from "@/components/ui/select";<Select label="Transfer purpose" options={[{ value: "rent", label: "Rent" }, …]} onValueChange={setPurpose} />Examples
States
A short list (5 options) opens without search. Don't preselect an option unless it's a safe default.
Icon and description
icon and description per option, and disabled for one that isn't available. The chosen row shows a check.
Multi select
MultiSelect: chosen options are tags in the field, each with a remove button; typing in the field filters the list; rows carry a checkbox and the list stays open until Done.
Multi select states
Past maxTags tags the field sums up the rest (“+2 more”) until it's focused; error and disabled as on Input Field; onCreate adds “Create new” with what the person typed.
API reference
Select
| Prop | Type | Default | Description |
|---|---|---|---|
label | ReactNode | Figma's Show label. | |
options | { value, label, description?, icon?, disabled? }[] | The options. | |
value / defaultValue | string | null | The chosen option's value. | |
onValueChange | (value: string | null) => void | When an option is picked. | |
searchable | boolean | options ≥ 8 | The search box at the top of the list. |
placeholder / searchPlaceholder / emptyText | string | Default: in the page language (“Choose an option”, “Search”, “No matches”). | |
name | string | Form field name. | |
required / helperText / error / disabled | … | As on Input Field. |
MultiSelect
| Prop | Type | Default | Description |
|---|---|---|---|
options | { value, label, description?, icon?, disabled? }[] | The options, as on Select. | |
value / defaultValue | string[] | The chosen options' values. | |
onValueChange | (value: string[]) => void | When options are picked or removed. | |
maxTags | number | 3 | Tags shown while the field isn't focused; the rest become “+N more”. |
onCreate | (query: string) => void | Adds a “Create new” button to the list footer. | |
placeholder / emptyText / name | string | As on Select (“Choose options”). | |
label / required / helperText / error / disabled | … | As on Input Field. |
Accessibility
Keyboard
Keys are written for left-to-right. In right-to-left the arrow keys swap: the one pointing toward the reading direction moves forward.
| Key | Action |
|---|---|
| EnterSpaceArrowDown | Opens the list. |
| ArrowUpArrowDown | Between options; Enter picks, Escape closes. |
| A–Z | In a short list: jumps to the option starting with the letter. In a long one: types into the search. |
| Backspace | Multi select, with nothing typed: removes the last tag. |
ARIA
- The field is a button tied to the label that opens a
listbox; the chosen option isaria-selectedand shows a visible check. - Helper text and errors are linked as on Input Field.
- Multi select: the field is
role="combobox", each row is one option witharia-selected(the checkbox is drawn, not a second control), the number chosen is announced (“3 selected”), and each tag has a “Remove” button with its name.
Arabic and RTL notes
Mirrors
- The caret sits at the end of the field (the left), and the row icon and check swap sides.
- The list carries the page direction and language, even when opened from an LTR island.
Does not mirror
- The caret points down in both directions; the check doesn't mirror.
- Numerals
- Numbers in options are as you write them; use
formatNumberfor amounts. - Arabic typography
- The field is
label-16; rowslabel-14Medium withlabel-12descriptions. - Mixed-direction text
- Each option and description takes
dir="auto": an English name in an Arabic list runs left to right.