Search field

Sits above a list or table and filters it ("Mitglieder suchen"). The label is visually hidden because the icon and placeholder make the purpose obvious — but it is always present for screen readers.

Filter as the user types (debounced ~250 ms) for local lists, or on Enter for server searches. Put the query into the URL (?q=…) so reload and back keep it (UX guide §3.3).

When nothing matches, show an empty state that repeats the query and offers to reset filters ("Keine Mitglieder für «Mueler»"). Announce result counts in a polite live region if the list updates while typing.

Examples

Member search

Data
render({
  "id": "member-search",
  "label": "Mitglieder suchen",
  "placeholder": "Name, z. B. Müller",
  "controls": "member-list"
})
Markup
<div class="search">
<svg class="icon" aria-hidden="true"><use href="../../packages/ui/icons/icons.svg#search"/></svg>
<label class="u-visually-hidden" for="member-search">Mitglieder suchen</label>
<input class="input" id="member-search" name="q" type="search" enterkeyhint="search" autocomplete="off" placeholder="Name, z. B. Müller" aria-controls="member-list">
</div>

With query from the URL

Data
render({
  "id": "exercise-search",
  "label": "Übungen suchen",
  "value": "Dollyo Chagi",
  "placeholder": "Übung oder Technik"
})
Markup
<div class="search">
<svg class="icon" aria-hidden="true"><use href="../../packages/ui/icons/icons.svg#search"/></svg>
<label class="u-visually-hidden" for="exercise-search">Übungen suchen</label>
<input class="input" id="exercise-search" name="q" type="search" enterkeyhint="search" autocomplete="off" value="Dollyo Chagi" placeholder="Übung oder Technik">
</div>

Data contract

What render(data) accepts — validated against this JSON Schema in development and tests. Unknown fields are rejected. The same schema is in components.json.

FieldTypeRequiredDefaultDescription
idstringrequired—Id of the input. Must be unique on the page.
pattern ^[A-Za-z][\w-]*$
labelstringrequired—Accessible label, visually hidden ("Mitglieder suchen").
min 1 chars
namestringoptional"q"Form field / query-string name.
valuestringoptional—Current query (e.g. restored from the URL).
placeholderstringoptional—Example of what can be searched ("Name, z. B. Müller"). Not a substitute for the label.
controlsstringoptional—Id of the list or table the search filters (aria-controls).
pattern ^[A-Za-z][\w-]*$
JSON Schema
{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "id",
    "label"
  ],
  "properties": {
    "id": {
      "type": "string",
      "pattern": "^[A-Za-z][\\w-]*$",
      "description": "Id of the input. Must be unique on the page."
    },
    "label": {
      "type": "string",
      "minLength": 1,
      "description": "Accessible label, visually hidden (\"Mitglieder suchen\")."
    },
    "name": {
      "type": "string",
      "default": "q",
      "description": "Form field / query-string name."
    },
    "value": {
      "type": "string",
      "description": "Current query (e.g. restored from the URL)."
    },
    "placeholder": {
      "type": "string",
      "description": "Example of what can be searched (\"Name, z. B. Müller\"). Not a substitute for the label."
    },
    "controls": {
      "type": "string",
      "pattern": "^[A-Za-z][\\w-]*$",
      "description": "Id of the list or table the search filters (`aria-controls`)."
    }
  }
}

Markup & states

Root: div.search — usable without render() by writing the markup directly.

Attributes

AttributeValuesDefaultDescription
type="search" (on input)——Search keyboard on phones, native clear button.
enterkeyhint="search"——Enter key labelled "Suchen" on phones.
aria-controls (on input)id—The filtered list.

Parts

PartDescription
svg.iconMagnifier, decorative, positioned inside the input.
label.u-visually-hiddenHidden label bound with for.
.inputThe search input with extra start padding for the icon.

States

StateDescription
:focus-visibleGlobal focus ring (from .input).

Accessibility

  • A real <label for> exists, only visually hidden — the placeholder is not the label.
  • The icon is aria-hidden.
  • If results update while typing, announce the count in a polite live region ("12 Mitglieder gefunden").

Guidance

DoKeep the query in the URL.
DoSearch across the fields people actually know (name, not member number only).
Don'tDon't hide the search behind an icon button on desktop.
Don'tDon't clear the query when the user opens a result and comes back.

Related: Form field · List · Table · Empty state