Components
Select
The one dropdown, plain or searchable, with groups, hints and an optional create row.
bunx shadcn@latest add @nalarx/selectUsage
<Select ariaLabel="Time zone" value={zone} onChange={setZone} options={zones} />
<Select ariaLabel="Owner" value={owner} onChange={setOwner} searchable groups={teams} />Secondary text, hints at size="sm", a searchable grouped list with a placeholder, a searchable list with a create row, an icon-only trigger, disabled:
States
- Placeholder:
ink-4whenvaluematches no option. - Open: the chevron turns; the panel is at least the trigger's width and at most
maxPanelWidth(360px) and the screen width. - Chosen option: semibold,
bg-hover, check on the right. - Disabled option: 55% in
ink-4, skipped by the keyboard. Disabled select: 50%. - Searchable: a search box tops the panel and filters by label, secondary text, hint and value. Nothing matching shows
emptyMessage. Empty groups disappear. - createOption: with flat
options, a typed query can add one more row (for exampleAdd "foo"); picking it callsonChangewith its value.
Keyboard
| Key | Plain | Searchable |
|---|---|---|
Enter, Space, ArrowDown on the trigger | Opens on the chosen option | Opens with focus in the search box |
ArrowDown / ArrowUp | Moves through options | Moves the highlight while you keep typing |
Home / End | First / last option | Caret start / end in the search box |
| Typing | Jumps to the option starting with the letters | Filters the list |
Enter | Picks and closes | Picks the highlighted option |
Escape | Closes, focus back on the trigger | Same |
Props
| Prop | Type | Default | |
|---|---|---|---|
value | T | ||
onChange | (value: T) => void | ||
ariaLabel | string | Names the trigger and the list. | |
options / groups | SelectOption<T>[] / SelectGroup<T>[] | groups wins. | |
placeholder | string | selectPlaceholder string | |
size | "sm" | "md" | "md" | 30px / 36px. |
width, minWidth | number | string | A number is pixels. | |
height | number | Overrides size. | |
searchable | boolean | false | |
searchPlaceholder | string | searchPlaceholder string | Also the search box's name. |
emptyMessage | string | noMatches string | |
maxPanelWidth | number | 360 | |
triggerContent | ReactNode | Replaces label and chevron. | |
createOption | (query, hasMatches) => SelectOption<T> | null | Searchable, flat options only. Keep it stable. | |
disabled, className |
SelectOption has value, label, icon?, disabled?, hint?, secondary?. filterSelectOptions is the search rule as a pure function.
Replaces
Select.tsx and ModernSelect.tsx in both apps; the Platform base/Select.tsx becomes an adapter (onValueChange → onChange, height={32}); the web base/Select.tsx is deleted.