Designer view
Search Input
A text input optimised for free-text search queries — typically pinned at the top of a search-driven page or in a navigation bar — with a leading magnifier icon, optional clear affordance, and optional results-preview popup. Distinct from Combobox by emitting a free-text query rather than committing a constrained value: search results live in a separate region (a search-results page or a results panel) rather than in the input's listbox. Distinct from plain Input by structuring the search-and-submit contract.
When to use
Use
For free-text search queries that route to a separate results region — site-wide search bars, in-page filter composers, search engines, document-finders, contact- pickers (where the result-set is long and unbounded). The user types intent, submits, and receives results elsewhere.
Avoid
For selecting a constrained value from a list — that is `Combobox` (commit-from-list semantics). For multi-value input where each value renders as an inline tag — that is `TagInput`. For free-text without search semantics — plain `Input`. For navigation menus styled as search — that is `MenuButton`.
Versus related
- combobox
`Combobox` commits a value from a constrained list (the input value is set to the selected option). `SearchInput` emits a free-text query that routes to a separate results region. They look similar with with-suggestions variant; the distinguisher is whether the popup contains options-to-commit (Combobox) or suggestions-to-fill-and-submit / result-previews-to- navigate (SearchInput).
- input
`Input` is generic free-text without search semantics — no canonical magnifier icon, no clear-on-Escape, no debounced typeahead architecture. `SearchInput` layers search-specific affordances on top of input.
- tag-input
`TagInput` accepts multiple discrete values rendered inline as tokens; `SearchInput` accepts a single free-text query. Multi-attribute search (filtering by multiple tags) is TagInput-shaped; single-query search is SearchInput-shaped. The two may compose — a search bar with both a TagInput for filters AND a SearchInput for query is a legitimate composite.
Figma anatomy
| Slot | Figma type | Hint |
|---|---|---|
root | frame | Auto-layout horizontal frame with input and decorative slots; min-inline-size from variant |
icon | instance | Magnifier icon component instance; non-interactive in default variant |
input | instance | Text input component instance; typeahead/suggestion variant adds combobox semantics |
clear-button | instance | Icon button instance; visibility bound to "has value" state |
submit-button | instance | Icon button instance; magnifier glyph; visibility bound to "has submit button" property |
results-popup | frame | Floating frame anchored to input; visibility bound to suggestions/results state |
Token usage per slot
root- spacing
- padding
spacing.compact - gap
spacing.tight
- padding
- radius
- corner
radius.md
- corner
- color
- background
color.surface.bg - border
color.border.strong - ring
color.border.focus
- background
icon- color
- foreground
color.text.muted
- foreground
input- spacing
- padding
spacing.tight
- padding
- color
- background
color.surface.bg - foreground
color.text.primary
- background
- typography
- size
text.md
- size
clear-button- spacing
- padding
spacing.tight
- padding
- radius
- corner
radius.sm
- corner
- color
- foreground
color.text.muted - ring
color.border.focus
- foreground
submit-button- spacing
- padding
spacing.tight
- padding
- radius
- corner
radius.sm
- corner
- color
- background
color.accent.bg - foreground
color.accent.fg
- background
Figma ↔ Code property map
| Figma | Type | Code | Notes |
|---|---|---|---|
Variant | Variant | variant | Maps standard / compact / with-suggestions. |
Size | Variant | size | sm / md / lg. |
Has Icon | Boolean | hasIcon | Toggles the leading magnifier icon. Default true; false for compact variant where the magnifier is the submit button instead. |
Has Clear | Boolean | hasClear | Toggles the clear button. Default true; visible only when input has a value. |
Has Submit | Boolean | hasSubmit | Toggles the submit button. Default false (Enter submits); true for compact variant or for forms where explicit pointer-submit is preferred. |
Placeholder | Text | placeholder | Examples — "Search products…", "Search documents…". Avoid placeholder-only labelling. |
Disabled | Boolean | disabled | — |
Icon | Instance Swap | icon | Swap the magnifier glyph; rare to deviate from the canonical magnifier. |
Motion
| Transition | Duration token |
|---|---|
clearTransition | motion.duration.fast |
suggestionsOpen | motion.duration.fast |
suggestionsClose | motion.duration.instant |
Responsive behaviour
| Breakpoint | Change |
|---|---|
breakpoint.sm | At and below, search inputs commonly expand to full inline-size of the parent (typical mobile pattern). For compact-variant in nav bars, the input may collapse to an icon-only state that expands to full- width on tap (the "search icon expands to input" pattern). Document the expand-on-tap as a separate property if used; otherwise assume inline expansion. |
breakpoint.md | Above this width, the input renders at its authored inline-size. Compact variant remains compact; standard variant uses its design-default width. |
Internationalisation
RTL · mirroring
Leading icon position moves from inline-start (visual left in LTR) to inline-start (visual right in RTL) via logical positioning. Clear button and submit button move from inline-end to inline-end (visual left in RTL). Magnifier glyph is direction-neutral; chevron glyphs (if used in suggestions) follow standard direction-neutral rotation. Input caret follows document direction; mixed-direction queries (typing Hebrew into a Latin-default field) honour the input's own `dir` attribute.
Text expansion
Placeholder text expands significantly in long-text languages — "Search products" → "Produkte suchen", "Поиск товаров", "Hae tuotteita". Allow input inline-size to grow; never truncate placeholder. Suggestion list inline-size matches input by default; long-text suggestions wrap to multiple lines or truncate with ellipsis (full text in `aria-label` for SR fallback).
Variants, properties, states
Variants
Structurally different versions of the component.
standardcompactwith-suggestions Properties
The same component, parameterised.
| Property | Type |
|---|---|
hasIcon | boolean |
hasClear | boolean |
hasSubmit | boolean |
size | sm | md | lg |
States
Browser/user-driven (interactive) vs. app-driven (data).
| Kind | States |
|---|---|
interactive | hoverfocus-visibleactivedisabled |
data | emptyfilledbusy |
State transitions
| From | To | Trigger |
|---|---|---|
empty | filled | User types into the input. Clear button (when `hasClear: true`) becomes visible; the canonical search-results pipeline begins (debounced query dispatch for with-suggestions variant; standard variant waits for explicit submit). |
filled | empty | User clears the input — via clear button, Escape key (closes results popup if open and clears value), form reset, or programmatic clear. |
filled | busy | For with-suggestions variant, the user types and the debounced query fires. Suggestions / preview-results request is in flight; the input shows a busy indicator (spinner or progress bar) and any open results popup shows a loading state. |
busy | filled | Async suggestions / results return. The popup renders the new results; busy indicator clears. |
Figma↔Code mismatches
- 01 Figma
SearchInput drawn with a results listbox below it (Combobox-style)
CodeA SearchInput that emits a free-text query for a separate results page, with no inline listbox
ConsequenceDesigners may compose SearchInput mocks with combobox- style results inline in the listbox. Implementations following the design ship a Combobox; users committing via Enter expect to navigate to a search-results page, but instead a value is silently set in the input. The contract diverges: search emits queries; combobox commits values.
CorrectDistinguish at the canonical level. SearchInput emits a free-text query on submit (Enter, button click) — the results live in a separate region (search-results page, sibling panel). Combobox commits a value from a constrained list — the value is set inline. Document the with-suggestions variant explicitly: the popup shows previews of results that link to the full results page, NOT options to commit as the input value.
- 02 Figma
SearchInput drawn without a clear button
CodeSearchInput with no clear affordance, requiring users to manually delete the query
ConsequenceDesigners may omit the clear button for visual simplicity. Implementations following the design ship without clear; users typing partial queries must manually backspace or select-all-delete to clear. `<input type="search">` browsers provide a native clear affordance at the OS level which the design may not account for, leading to inconsistent visual treatment.
CorrectThe clear button is canonical when `hasClear: true` (default). For native `<input type="search">` the browser provides one for free; styled SearchInputs that override the native clear must provide their own. Document the canonical contract: clear visible when input is non-empty.
- 03 Figma
Magnifier icon drawn as a static decoration
CodeA magnifier icon that may be either decorative (leading) or interactive (submit button trailing)
ConsequenceDesigners may draw the magnifier as a leading visual decoration; developers ship it as a button. Or designers draw it as a button; developers ship it as a decoration. The clickable-vs-decorative status is not encoded in the Figma file.
CorrectThe leading icon (`anatomy.icon`) is decorative. The submit button (`anatomy.submit-button`) is a real button. Document the variant-driven choice: standard variant has both (decorative leading + optional trailing submit button); compact variant uses the magnifier as the submit button (the only icon).
- 04 Figma
Search suggestions drawn looking like search results
CodeSuggestions that auto-complete the query vs results that link to specific items
ConsequenceDesigners compose with-suggestions variant mocks that visually conflate "query autocompletion" with "result preview". Users clicking a suggestion expect either to navigate to a result OR to fill in the query and submit; the two intents are different.
CorrectThe popup hosts one of two distinct content types: query suggestions (text strings that, when activated, fill the input and submit) OR result previews (links that navigate directly to the result). Document the distinction; surface it visually (suggestions look like input completions; result previews look like list rows with title/description).
Common mistakes
#searchinput-as-combobox
SearchInput implemented as a Combobox with constrained values
The implementation uses Combobox semantics — committing from the listbox sets the input value. Users typing free-text searches that do not match any option get silently rejected on commit; the search query never fires.
SearchInput emits free-text queries; the results popup is for previewing, not for committing as the input value. Use `role="searchbox"` (input type="search") for the input; if the with-suggestions variant adds a listbox, the listbox items are clickable suggestions that fill-and-submit, not commit-and-set.
#searchinput-no-debounce
Suggestion request fires on every keystroke without debouncing
The with-suggestions variant fires a request on every character typed. Users with fast typing flood the backend; results race conditions render stale data.
Debounce typeahead requests by ~150ms. Below the perceptual threshold of feeling laggy; suppresses 80%+ of in-flight stale requests on a 60–80 wpm typer. Cancel in-flight requests when a newer one fires.
#searchinput-no-submit-on-enter
Enter key does not submit the query
The implementation captures Enter for some other purpose (closing the popup, blurring the input). Users pressing Enter expect to commit the search; nothing happens.
Enter on the input always submits the search query. For the with-suggestions variant where Enter-with-highlighted- suggestion may select-and-submit, Enter-without-highlight submits the typed query verbatim. The submit-button activation is equivalent.
#searchinput-clear-doesnt-restore-results
Clear button removes the query but leaves stale results
User clears the search; the results page or panel still shows the old results. The state diverges — the input is empty, but the results pretend the search is active.
Clear button activation must reset the associated results region back to its empty / default state. Document the canonical contract: query state and results state are coupled; clearing one clears the other.
#searchinput-results-popup-no-aria
With-suggestions popup has no `aria-live` or listbox structure
The popup renders suggestions but SR users hear nothing — no listbox role, no aria-live status. They type, get no feedback, and may submit empty queries without knowing suggestions exist.
For typeahead suggestions, the popup is `role="listbox"` with `aria-activedescendant` driving the announcement. For result-previews, the popup is `role="region"` with a polite live region announcing result counts ("12 results"). The two patterns are distinct; document both contracts.
Accessibility hints
| Slot | Accessibility hint | |
|---|---|---|
root | Apply `role="search"` (or `<search>` element where supported) when the input is the page's primary search landmark. For inline search inputs inside other regions (a filter inside a settings panel), no landmark role is needed — the input alone is sufficient. | |
icon | Decorative — `aria-hidden="true"`. The accessible name comes from the wrapping label or from `aria-label` ("Search products"); the magnifier glyph is not a substitute. | |
input | `<input type="search">` is the canonical default. For with-suggestions variant, layer the Combobox contract (`role="combobox"`, `aria-controls` referencing the results popup, `aria-activedescendant` for the highlighted suggestion). The accessible name comes from a paired `<label>` or `aria-label`. Avoid placeholder- only labelling. | |
clear-button | Real `<button>` with accessible name ("Clear" or "Clear search"). Activation clears the input value, returns focus to the input, and may reset associated results. Escape with focus on the input also clears (per APG Combobox guidance and `<input type="search">` platform default). | |
submit-button | Real `<button type="submit">` (when nested in a `<form>`) or `<button>` with explicit submit handler. Accessible name "Search" or "Submit search". Enter on the input also submits — the button is an additional affordance, not a replacement. | |
results-popup | For typeahead suggestions, `role="listbox"` plus `aria-activedescendant` on the input. For live result- preview (a search engine surfacing top hits), the popup is `role="region"` with an `aria-live="polite"` status announcing result counts. The two patterns are distinct and the popup's role differs accordingly. |