Search field
StableA pill-shaped search input that filters what is already on screen: a list of orders, a product picker, a menu of options. To search the whole of Orbit, people use the command palette instead.
Playground
Change the props, then type into the pill: the keycaps fade and a clear button pops in where they were.
<SearchField
aria-label="Search products"
placeholder="Search by name or SKU"
/>Filtering a list
Control the query with value and onValueChange, and filter as people type. Say how many results match, and when nothing does, repeat the query and offer a way back.
The shortcut caps are only a hint, shown while the field is empty and idle. Bind the key yourself: this example binds /, so press it anywhere on the page.
- Arden ergonomic chair, blackARD-CHR-BLK14 in stock
- Arden ergonomic chair, greyARD-CHR-GRY3 in stock
- Harbour oak desk, 140cmHBR-DSK-1406 in stock
- Harbour oak desk, 160cmHBR-DSK-160Out of stock
- Linen desk matLIN-MAT-00142 in stock
- Brass task lampBRS-LMP-0029 in stock
- Walnut monitor standWAL-STD-00117 in stock
- Cable tidy trayCBL-TRY-00158 in stock
Clearing
Once there is a query, a round clear button pops in where the keycaps were. Pressing it empties the field, calls onValueChange('') and then onClear, and puts focus back in the field.
Escape does the same from the keyboard, and it clears before anything else hears it. Inside a dialog or popover, the first Escape clears the search and only the next one closes the dialog. Open the dialog, type and press Escape twice.
Keyboard
| Key | What it does |
|---|---|
| Escape | With a query: clears it and stops there, even inside a dialog. With an empty field: passes on, so it can close the dialog or popover around it. |
| Enter | Nothing built in. Inside a form it submits the form, like any search input. Phone keyboards label the key Search. |
| Tab | The clear button is left out of the Tab order: Escape does its job from the keyboard. |
| Your shortcut | Only drawn, never bound. Bind it in your page, as the list example binds /. |
Sizes
md 36px (default) and sm 30px, the same heights as buttons, so a search sits in a toolbar row with them. There is no large search.
With a label
Most searches are named by what sits around them, so an aria-label is enough. When a visible label helps, as in a filter panel, put the search in a Field: it picks up the label and the hint.
Name, email or postcode
On the ground
On the app's ground, as in a side panel, the pill still stands off the surface, and so does its focus halo.
Search field or command palette?
They look alike on purpose, and they do different jobs. The header's SearchTrigger is a button that opens the command palette; SearchField is a real input that filters in place.
| Question | SearchField | SearchTrigger |
|---|---|---|
| What it is | A text input. | A button shaped like a search pill. |
| When you type | Filters what is on this page as you type. | Opens a panel that searches the whole of Orbit and jumps to the result. |
| Where it goes | Above a list or table, in pickers, popovers and dialogs. | Once, in the app header. |
| Shortcut | Optional caps, often /. You bind the key. | ⌘K on a Mac, Ctrl K elsewhere, bound for you. |
While results load
SearchField has no loading state. When results come from the server, show the wait where the results will appear, with skeleton rows or a spinner in the list, and keep the field free to type in.
In both themes
Empty with a shortcut, with a query, small and disabled, light and dark side by side.
Guidelines
- Give it a name as well as a placeholder: an aria-label or a Field label. A placeholder is not a name.
- Show how many results match, and an empty state that repeats the query.
- For searches that go to the server, wait for a short pause in typing before asking.
- Never put a SearchField in the app header for searching everything: that is the command palette.
Accessibility
- Renders
input type="search", announced as a search field. Name it witharia-labelor a Field label. - The magnifier and the shortcut caps are hidden from assistive tech.
- The clear button is named by
clearLabel("Clear search"), is hidden from assistive tech while the field is empty and is left out of the Tab order. After clearing, focus goes back to the field. - Escape clears before any dialog or popover hears it, so clearing a search never throws someone out of the dialog.
- Autocomplete and spellcheck are off; phone keyboards show a Search key.
- Result counts are not announced for you. Put them in a
role="status"element, as the list example does. - Focus shows as a teal edge and soft halo round the pill. Under reduced motion the clear button fades in without the pop.
Props
Other native input attributes, and the ref, go to the input. className and style go to the pill.
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | None | The query, when you control it. |
defaultValue | string | '' | The starting query when uncontrolled. |
onValueChange | (value: string) => void | None | Called with the query on every keystroke, and with an empty string on clear. |
onClear | () => void | None | Called after the clear button or Escape empties the field. |
size | 'sm' | 'md' | 'md' | 30 or 36px tall. |
shortcut | string[] | None | Keycaps shown while empty and idle, e.g. ['/'] or ['mod', 'K']. Drawn only: bind the keys yourself. |
placeholder | string | 'Search' | What can be searched. Not a name. |
clearLabel | string | 'Clear search' | The clear button's accessible name. |
disabled | boolean | None | Sinks into the well; the field and its clear button stop responding. |