Search

search.search

Search — a search field with a leading icon, inside the <search> landmark.

Examples

A search landmark

View “A search landmark” as
<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.

The glyph at the other end

View “The glyph at the other end” as
<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.

Level 2 tokens declared by search
TokenDefault
--search-icon-colorvar(--color-on-surface-muted)
--search-icon-gapvar(--space-2)
--search-icon-insetvar(--space-3)
--search-icon-sizevar(--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

  1. Give it a <label>. A placeholder is 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 is aria-hidden and names nothing.
  2. Keep aria-hidden="true" on the <svg>. It repeats the label.
  3. Name the landmark when a page has more than one — aria-label on the <search> — so "search" is not announced twice with nothing to tell the two apart.
  4. With .search-trailing, write type="text" role="searchbox" enterkeyhint="search" — all three. The variant needs type="text" to remove the clear control it would otherwise sit under, and type="text" alone announces the field as a plain textbox in every engine. The role and the hint are what type="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