Search
Search — a search field with a leading icon, inside the <search> landmark.
Examples
<search class="search">
<label class="sr-only" for="site-search">Search the documentation</label>
<svg class="icon search-icon" aria-hidden="true"><use href="#icon-search"></use></svg>
<input class="input search-input" id="site-search" name="q" type="search" placeholder="Search" />
</search><search> is the landmark element and is Baseline, so role="search" on a <form> is no longer needed. The input still needs a label — a placeholder is not one, it disappears the moment you type.
<search class="search search-trailing" aria-label="Filter the list">
<label class="sr-only" for="list-filter">Filter the list</label>
<input class="input search-input" id="list-filter" name="filter"
type="text" role="searchbox" enterkeyhint="search" placeholder="Filter" />
<svg class="icon search-icon" aria-hidden="true"><use href="#icon-search"></use></svg>
</search>All three attributes are required, and why they are is the whole variant.
type="text" is what removes the browser's own clear button, which otherwise sits exactly where this glyph goes — two overlapping controls on Chromium and WebKit, one on Firefox. But type="text" alone announces the field as a plain textbox in all three engines, so role="searchbox" puts back what type="search" was giving you and enterkeyhint="search" puts back the labelled Go key on a touch keyboard. You do still lose the clear button, which is a real affordance on a phone: reach for this when the field filters a list in place, and keep the default when the search submits and navigates.
Tokens 4
Level 2, declared on .search itself. Set any of them on that selector to restyle this component without touching the skin.
| Token | Default |
|---|---|
| --search-icon-color | var(--color-on-surface-muted) |
| --search-icon-gap | var(--space-2) |
| --search-icon-inset | var(--space-3) |
| --search-icon-size | var(--font-size-base) |
Variants and states
Variants
.input-lg.input-sm
Inside it
.search-icon.search-input.search-trailing.search-box
State it reads
Read from the platform, never mirrored into a class that could disagree with it.
:disabled
Before you ship it
What you have to do 4 requirements
- Give it a
<label>. Aplaceholderis not a label: it disappears on the first keystroke, is not reliably announced, and its contrast is deliberately low. Where the design has no room for visible label text, use<label class="sr-only">— the label still exists, it is just not painted. The magnifier isaria-hiddenand names nothing. - Keep
aria-hidden="true"on the<svg>. It repeats the label. - Name the landmark when a page has more than one —
aria-labelon the<search>— so "search" is not announced twice with nothing to tell the two apart. - With
.search-trailing, writetype="text" role="searchbox" enterkeyhint="search"— all three. The variant needstype="text"to remove the clear control it would otherwise sit under, andtype="text"alone announces the field as a plain textbox in every engine. The role and the hint are whattype="search"was giving you for free; nothing detects their absence and nothing renders differently without them.
src/css/components/search.css · npx mostlycss add search