SearchApi Design System

Components

      • Playground
      • All variants
      • States
      • Full width
      • Playground
      • Variants
    • Locale Switcher
    • Site Footer
      • Playground
      • Every preference
      • Playground
      • Every preference
      • HTTP request
      • Every token kind
      • Playground
      • Every target
      • Playground
      • Slots
      • Sunk body
      • Plan comparison
      • Numeric columns
      • Parameter reference
      • Payload
      • With drill-in tokens
      • An error envelope
      • All meanings
      • Playground
      • Every service
      • Playground
      • Lettermark
      • Playground
      • Named and decorative
      • Default
      • In a value list
      • Playground
      • Playground
      • In a row
      • Playground
      • Default
      • With type
      • Required
      • In context
      • Current
      • Sizes
      • States
      • Composed
      • Playground
      • Playground
      • Multiline
      • Playground
      • Required, default and set rows
      • With a validation error
      • With a handed-in token
      • Playground
      • Requiredness
      • Defaults and enums
    • Playground
      • Playground
      • With parameters set
      • No recording, Run disabled
      • Playground
      • Handed in from another engine
      • With a validation error
      • Playground
      • Multiple
      • Closed
      • Results view
      • Sidebar
      • Panel
      • Lettermark services
      • Playground
      • Renders nothing
      • Playground
      • Variants
      • Export switcher
    • Engine Page Header

No matching results.

Pages

  • Foundations
  • Colour
  • Typography
  • Radius & shadow
  • Motion
  • Data states
  • Parameter vocabulary
  • Form controls

No matching results.

Form controls

Form controls

One control vocabulary, read by every editable surface. Before it, the app had five private ones — a text/select bundle at one size, the parameter table's two hand-written controls, the request bar's box and the tree filter — with four different focus answers and no shared height. A reader crossing the playground met a 44px address field, a 34px grid cell and a 30px filter, each answering a click differently, and learned the interface three times.

InputComponent and SelectComponent are that vocabulary now, over one geometry scale and one state contract in ControlStyles. Everything below is rendered from those components and the same tokens the rest of the pipeline is generated from.

The scale, and where each size goes

A size is a box, not a typeface: it fixes height, inline padding and radius, not how hard the value is to read.

Size Box Text Where
sm 28px 14px parameter-table cells, the tree filter
md 36px 14px every form on a page — the default
lg 44px 16px the request address; touch targets

sm and md share 14px type on purpose. The sm size exists for the parameter table, and the parameter table is where a reader reads values — coffee shops berlin, 227 country codes. A 12px mono value in a grid is a legibility defect; "small" here means the box got tighter, not that the content got harder to read. lg steps to 16px because it is the one control on screen the whole time and the one a thumb aims at.

The seven states, once

Rest, hover, focus, filled, read-only, disabled and error are defined once and are identical on input and select at the same size — an input and a select of the same size are the same box, which is the whole claim. Hover deepens the border to ink-faint, never the accent: a hover that lit the accent read as a promise of action rather than as a hover.

The hover and focus rows above are drawn by preview-only classes the template declares — a static page has no pointer. They exist nowhere in the application's stylesheet.

Focus is the family's one exception

The site's global recipe is :focus-visible { outline: 2px solid accent-line }, and every button, link and icon control keeps it. Text and select controls take a different one — an accent-line border plus a 3px focus-ring, on :focus, with the outline suppressed — because :focus-visible does not match a mouse click into an input on every engine, and a caret blinking inside a 1px box is not a state. This is the family's only departure from the global recipe, it is declared once, and it adds no second ring to buttons or links.

Suppressed means suppressed in the stylesheet, beside the recipe it excepts — not by the control's own outline-none. The global rule sits outside every cascade layer so that a utility cannot silently remove a focus state, which means a utility cannot remove this one either: the family's border and ring shipped under the global outline until the stand-down was written, and a focused field wore two borders for one state. The exception names the controls that draw their own focus and leaves the outline to everything that does not — a checkbox, a radio and the browser's own widgets have no other focus state to fall back on.

Error is a border and a sentence

An invalid control carries a 1px border and ring in the status-error role and aria-invalid; the surface that owns the control — the parameter grid's cell — states the message beneath it in that same role. The old 2px-border trick is gone — a weight change is not a state a reader can name — and a validation message is a sentence, not a Badge: a Badge labels a meaning, and the control never recolours its own value.

Quiet is a variant, not an absence

The parameter table's cell is already ruled on three sides, so a bordered field inside it states the same edge twice. quiet withholds the resting border and fill and gets them back on hover and focus — the family's own border, the family's ring, the family's disabled treatment. A quiet control is a skin, never a different control, which is the sentence that keeps the next person from re-inventing a borderless input somewhere else.

Deliberately not done

  • No custom listbox. The native select's viewport handling, type-ahead and phone behaviour are worth more than a matching chevron animation; the only thing appearance: none costs is the arrow, which the family draws.
  • No size below 28px, and no fourth size — the densest surface there is is comfortable at 28px.
  • No 12px control type at sm — a 12px mono value in the grid is a legibility defect, not a density setting.
  • No red error text inside a control, and no checkbox/radio redesign — the send box and the segmented control keep their markup and only join the scale.
Parameter vocabulary