Select
Picks one option from a list that pops up.
Examples
Sizes
sm
mddefault
lg
States
rest
placeholder
hover
focus-visible
open
invalid
disabled
Usage
When to use it
- Use
- One of 6 to 20 options: an account, a currency, a country.
- Use
- A form where a list of radios would take too much room.
- Not for
- Two to five options fit in a row. Use Segmented.
- Not for
- The options are a short list of radios. Use Radio.
- Not for
- More than about 20 options, or the person knows the name. Use Combobox.
- Not for
- The options are commands, not values. Use Dropdown menu.
Rules
9 rules
- Must
- Pass items to the root so the trigger shows the label before the popup opens. Because without items the trigger shows the raw value, such as savings, until the first open.
- Must
- Use placeholder on the trigger; never an item called "Select...". Because an empty item can be picked, checked and submitted as a real answer.
- Should
- Show five or fewer options as Radio or Segmented when there is room.
- Never
- Use a native select; this Select matches the popup, check and focus. Because the native picker is drawn by the OS, with no Lime panel, check mark or accent edge.
- Must
- Pass aria-label to the trigger when there is no visible label. Because a screen reader reads the chosen account with nothing saying what it pays from.
- Must
- Wrap the select in Field with a FieldLabel, and put errors in FieldError. Because Field ties the label and the error to the trigger, so both are read with it.
- Should
- Write short sentence-case noun labels with the distinguishing word first.
- Never
- Lift the popup height cap; lists scroll inside --popup-max. Because a long account list runs past the screen edge instead of scrolling inside the panel.
- Should
- Use size="lg" on the trigger in a phone form; items are 36px.
Accessibility
4 checks
- The trigger is role combobox with aria-expanded; the popup is a listbox of options.
- Enter, Space or Arrow Down opens; arrows, Home, End and type-ahead move; Enter chooses; Escape closes.
- Focus returns to the trigger on close; Escape in a dialog closes the popup first.
- A highlighted item has only a fill, so forced colors paints it with Highlight.
Edge cases
6 edge cases
- Long label
- Trigger and items truncate with an ellipsis; keep labels short or widen the trigger.
- Narrow container
- The trigger has a 160px floor; set w-full min-w-0 to follow the container.
- Right to left
- Caret, padding and check mirror.
- No items
- The popup opens empty; render text instead of an empty Select.
- List loads late
- There is no loading row; render the select when items arrive.
- Inside a dialog
- The popup portals into the Lime scope and keeps the tokens.
API
5 props
itemsArray<{value, label}> | Recordvalue, defaultValue, onValueChangeValueSelectTrigger size'sm' | 'md' | 'lg'default'md'SelectTrigger placeholderstringSelectItem valueValuedefaultrequired
Tokens
20 tokens
--field- #f6f5f2
--line-strong- #cfcdc6
--fg- #0f0f0d
--fg-3- #6b6a63
--control- #85827a
--accent-line- #7c8700
--ring- var(--accent-line)
--line-focus- 2px
--danger- #d93636
--surface-2- #efeeea
--fg-disabled- #a6a49b
--raised- #ffffff
--shadow-menu- 0 8px 24px -6px rgb(var(--shadow-ink) / 0.16), 0 2px 6px rgb(var(--shadow-ink) / 0.06)
--radius-panel- 16px
--radius-md- 10px
--popup-max- 320px
--dur-base- 200ms
--dur-fast- 140ms
--ease-out- cubic-bezier(0.16, 1, 0.3, 1)
--scale-enter- 0.97