Skip to the page
Tactile UI

Kit part · Inputs · Search bars

Search field

A recess for a question. A glass is printed on its floor at the start, the words run on, an optional count is printed behind an engraved line, and a clear key sits in the far corner while there is something to clear. Escape empties it.

Element
<tui-search-field>
Needs
kit.css + kit.mjs
Rules
search-field.rules.md · 6
Finishes
Aluminium · Graphite · Oak · Walnut · Porcelain · Black · Daylight · Night · Paper · Phosphor · E-paper · AMOLED
Volumes
Tactile · Quiet
On this page
  1. Variants
  2. Every state, at once
  3. API
  4. Markup
  5. Accessibility
  6. How it’s built
  7. Rules
  8. Related parts

Seats open in 11 days. Want one email that morning?

Variants

Empty
Typed · clear key
3 of 8 runs
With a count
No runs
No results
8 runs
Count before typing
Disabled

Every state, at once

Both finishes, side by side. Hover, pressed and focus are forced with .is-hover, .is-down and .is-focus; checked and disabled are real.

Aluminium

PartRestTypedKey hoverKey pressed
Field
In focus

Graphite

PartRestTypedKey hoverKey pressed
Field
In focus

API

NameKindValuesWhat it does
<tui-search-field>elementaround the glass, input, count and keyThe well. Without the script it is the same well round a search input.
input.tui-search-field__inputelementtype="search"The real field. It posts, and Enter submits a form around it. Give it a name with aria-label or a label.
button[data-search-clear]attributeempty button at the endThe clear key. The script gives it its glyph and name, and shows it only while there is text.
output.tui-search-field__countelementoptional, before the keyWhere the count is printed. Hidden while it is empty.
count · total · unit · pluralattributenumbers and wordsThe count and what it counts: count="3" total="8" unit="run" prints “3 of 8 runs”. plural is for words that do not take an s.
countpropertynumber | nullThe number printed; null removes the count.
input · changeeventfrom the inputFire for typing, for Clear and for Escape alike, so one listener does the filtering.
searchCountText(count, options)function{ total, unit, plural }The words a count prints: “No runs”, “1 run”, “3 of 8 runs”. Pure.
Escape · Enter · Tabkeyin the fieldEmpties it, and goes no further while there was text; submits a form; moves to the clear key.

Markup

<search>
  <tui-search-field count="8" unit="run">
    <span class="tui-search-field__glyph" aria-hidden="true"><svg class="tui-icon" …></svg></span>
    <input class="tui-search-field__input" type="search" name="q" aria-label="Find a run" autocomplete="off">
    <output class="tui-search-field__count"></output>
    <button class="tui-search-field__key" type="button" data-search-clear></button>
  </tui-search-field>
</search>

<!-- A visible label above, as any field -->
<div class="tui-field">
  <label class="tui-label" for="q">Find a run</label>
  <tui-search-field>…</tui-search-field>
</div>
import { searchCountText } from '/kit/kit.mjs';

const field = document.querySelector('tui-search-field');
field.input.addEventListener('input', () => {        // typing, Clear and Escape all fire this
  const hits = runs.filter((r) => r.title.includes(field.input.value));
  render(hits);
  field.setAttribute('total', runs.length);
  field.count = hits.length;                          // prints "3 of 8 runs" and says it aloud
});

searchCountText(0, { unit: 'run' });                 // "No runs"
searchCountText(3, { total: 8, unit: 'run' });       // "3 of 8 runs"

Needs kit.css and kit.mjs. How to install the kit.

Accessibility

  • The field is a native type="search" input with a visible label or an aria-label; wrap it in <search> (or a form with role="search") when it searches the whole page or site.
  • The count is an <output>, a polite live region, so “3 of 8 runs” and “No runs” are said as the list changes without taking the focus.
  • The clear key is a real button named “Clear search”, in the tab order after the field and only while there is text. Pressing it, or Escape, empties the field and leaves the focus in it.
  • Escape clears only when there is something to clear, and then stops there, so a dialog around the field stays open until it is pressed a second time.
  • The glass is printed, not pressed, and is hidden from a screen reader.
  • On a phone the well is 48px tall with a 16px text size, so the page does not zoom, and the clear key is 44px. The 70ms press is switched off under reduced motion.

How it’s built

It is the field’s well, 38px high, with the glass printed on its floor and the count set behind the same engraved line the input group uses for its words. The clear key is a small cap inset three pixels from the wall, so its corner is the well’s less that gap. The native cross of a search input is turned off so there is one clear key, not two. The script keeps the key in step with the text, says the count aloud, and turns Escape into a clear; filtering is the page’s own job and listens for input.

Rules

search-field.rules.mdIn the brain

Filter a list as you type, say how many it found, and let Escape or one key start again, with nothing built but the well.

6 rules in this file, with the foundations they rest on and the anti-patterns that break them. Full rules ship in the brain with the Pass.

Field

Text entry in a recess, the label printed above it, and a hint that says how to fix an error.

Input group

One recess that holds a field and everything that belongs to it. Words that are part of the value but are not typed, such as https:// or a currency, are printed on the floor of the well behind an engraved line; a glyph sits at the start; small keys sit at the end to clear the text, copy it, or show a password.

Combobox

A field that filters a long list as you type. It starts as a plain select, so it posts with the form and works without a script; then the options card slides out of a slot under the well, the letters that match print heavier and the chosen option’s lamp is lit. Several choices sit in the well as tags.

Command palette

Every action and page behind one key: a modal plate whose entry line is a lit display, with the results printed below and the chosen one pressed in.