An Input with a magnifier in front and a clear button behind once there is a query.
Light
Empty
Search techniques…Focus
Search techniques…With a query · clear appears
kataWith filter chips below
Search students…BrownNeeds waiver
Dark
Empty
Search techniques…Focus
Search techniques…With a query · clear appears
kataWith filter chips below
Search students…BrownNeeds waiver
Source:
SearchField.tsx. When a screen gets search, filters, both or neither: search-filter.
When to use it
- At the top of an index long enough to need it — the search-filter chapter gives the counts.
- First on the screen, above any filter chips, so the field and the chips stay put while the results change below them.
Not for a list of ten rows a person can scan. Not as a form field — a search is a query, not a value that gets saved.
Anatomy
| Part | Token |
|---|---|
| Frame | the input's: surface.card, 1px border.control, radius.input, 44 floor |
| Horizontal padding | spacing.s12; slots and text separated by spacing.s8 |
| Leading glyph | search at iconSize.inline 16, text.tertiary |
| Query | typography.body 15/400, text.primary |
| Placeholder | text.tertiary |
| Clear | close at 16 in text.tertiary, hitSlop to a 44pt target; only when there is a query and onClear is set |
States
- Empty: magnifier and placeholder.
- Focus: 2px
border.focusframe, exactly as the input. - With a query: the clear button appears. Clearing keeps focus in the field.
- Results loading: the previous results stay visible; the list never blanks per keystroke.
- No results: the field and chips stay on screen, and the list says what matched nothing.
- Disabled, error: none of its own.
Content
- The placeholder names what is searched: "Search students…", never bare "Search".
- Never autofocus it on a tab home. A keyboard over the content someone came to browse is the most hostile thing a list screen can do.
Accessibility
- Role
search, and the return key is "search". - The accessible name defaults to the placeholder, which already says what is searched.
- The clear button is its own stop: role
button, "Clear search", testID<testID>-clear.
Do and don't
Search students…
Do
The placeholder names what is searched.
Search
Don’t
Bare “Search” leaves the scope to guesswork.
Code
import { SearchField } from '../../components/ui';
<SearchField
value={query}
onChangeText={setQuery}
onClear={() => setQuery('')}
placeholder="Search students…"
testID="roster-search"
/>