Combobox

Narrows a long list as you type, so you find the right item fast.

Examples

Find a friend

Pick a currency

Buttons

  • triggerdefault

  • showClear

  • hideTrigger

States

  • rest

  • chosen

  • hover

  • focus

  • invalid

  • disabled

  • open

Usage

When to use it
Use
A long list: more than about 20 options.
Use
The person knows the name: a friend, a merchant, a country.
Not for
Up to about 20 options and no need to type. Use Select.
Not for
Free text with no list. Use Input.
Not for
Two to five options. Use Radio.

Rules

10 rules
Must
Put a Combobox in a form inside Field with a FieldLabel; use aria-label only where there is no visible label, such as a toolbar. Because the visible label names the input for everyone, and a placeholder vanishes once the person types.
Must
Pass aria-label to ComboboxInput when there is no visible label; the placeholder is not a name. Because without it a screen reader announces an unnamed combobox once typing hides the placeholder.
Must
Include a ComboboxEmpty that says what was searched. Because ComboboxList hides itself when empty, so the popup opens on nothing.
Must
Pass items to the root and render ComboboxList with a function; do not map the array yourself. Because a mapped array skips the root's filter, so typing never narrows the list.
Should
Filter on the server and control inputValue when the list is too large to send.
Must
Set itemToStringLabel when items are objects. Because an object with no label key shows and filters on its serialized JSON.
Should
Name the thing to find in the placeholder, not Search...
Never
Write an input with a datalist; use this Combobox. Because a datalist draws browser chrome that ignores Lime's tokens and has no empty message.
Should
Use hideTrigger on phones; the 28px buttons are under the touch guideline and typing opens the list.
Never
Remove the list max height; it scrolls at 288px. Because 200 countries then run past the screen edge with no scroll inside the popup.

Accessibility

4 checks
The input is role combobox with aria-expanded, aria-controls and aria-activedescendant; the list is a listbox of options.
Typing filters; Arrow Down and Up open and move the highlight; Enter chooses; Escape closes, then clears.
Focus stays in the input while the list is open.
The clear and caret buttons are named "Clear" and "Show options".

Edge cases

7 edge cases
Long names
Items truncate with an ellipsis and no tooltip; keep names short.
500 items
Render and scroll inside the 288px list; the popup follows the input width.
Right to left
The buttons and the check move to the end edge on the left.
No items
The list hides and ComboboxEmpty shows; an empty query shows the whole list.
Server filtering
No loading row; keep the previous items until the new ones arrive.
Inside a dialog
The popup portals into the Lime scope; Escape closes the list first.
Forced colors
The input keeps its border; the highlighted item takes Highlight.

API

7 props
items
Array
value, defaultValue, onValueChange
Value
inputValue, onInputValueChange
string
itemToStringLabel
(item) => string
ComboboxInput showClear
boolean default false
ComboboxInput hideTrigger
boolean default false
disabled
boolean default false

Tokens

19 tokens
--field
#f6f5f2
--line-strong
#cfcdc6
--control
#85827a
--accent-line
#7c8700
--ring
var(--accent-line)
--danger
#d93636
--radius-field
12px
--fg-3
#6b6a63
--surface-2
#efeeea
--fg
#0f0f0d
--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
--fg-disabled
#a6a49b
--dur-base
200ms
--dur-fast
140ms
--ease-out
cubic-bezier(0.16, 1, 0.3, 1)
--scale-enter
0.97

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.