Skip to main content

Search

A text input that lets users search or filter content, with live suggestions as they type. Use for any search or filter interaction across the product. Don't use a standard Input field for search interactions.

OverviewStyleAccessibility

Description

Anatomy

PartRequired?Notes
Search container Required Wraps the entire control. Carries role='search' (or is nested inside a <form role='search'>) to expose the landmark to assistive technology.
Search icon Recommended Magnifying-glass icon rendered at the leading edge of the input. Provides a visual affordance. Hidden from the accessibility tree with aria-hidden='true' — the input's label conveys purpose.
Text input Required The editable field. Receives focus, accepts keyboard input, and fires input/change events that drive filtering or suggestion logic.
Clear button Optional Appears when the field has a value. Allows one-click dismissal of the current query. Must have an accessible label — 'Clear search' — and return focus to the text input after activation.
Suggestions dropdown Optional A listbox that appears beneath the input when live suggestions are enabled. Each option is a focusable listbox item. Dismissed on Escape or when focus leaves the composite.
Label Required Visually hidden labels are acceptable for compact nav-bar placements, but a visible label is required on standalone search panels. Always present in the DOM for screen readers.

Variants

States

State Behaviour
Default (empty) Placeholder text is visible. Search icon is shown. Clear button is hidden. Suggestions dropdown is closed.
Focus 3px focus ring using --op-color-interactive-focus appears around the input container. Suggestions dropdown may open if the field already has a value.
Active (has value) Placeholder is replaced by user input. Clear button becomes visible. If suggestions variant, the dropdown opens and filters to matching options.
Loading A spinner replaces or supplements the search icon to indicate an async lookup is in progress. The input remains editable. Announce 'Loading results' to screen readers via a live region.
No results Suggestions dropdown shows a single non-interactive message item — 'No results found' — when the query matches nothing. Does not close the dropdown automatically.
Disabled Input is non-interactive. Visually dimmed using --op-color-text-disabled and --op-color-bg-disabled. aria-disabled='true' is set. Do not use disabled for loading states — use the Loading state instead.
Error Border switches to --op-color-status-error. An error message appears below the input. Rare for search — typically used when a query format is invalid (e.g. special characters not permitted).

Usage guidelines

Do / Don't

Do

Always provide a visible or visually hidden label. Never rely on placeholder text alone as the label.

Don't

Do not use placeholder text as a substitute for a label — placeholder disappears on input and is not reliably announced by all screen readers.

Do

Use role='search' on the wrapping landmark so screen reader users can navigate to the search region directly.

Don't

Do not wrap the search input in a generic div without a landmark role — it becomes invisible to assistive technology navigation.

Do

Debounce live-search queries by 200–300ms to avoid firing a network request on every keystroke.

Don't

Do not fire search requests on every keydown — this creates excessive network load and degrades performance on low-bandwidth government networks.

Do

Announce result counts to screen readers using a live region: 'Showing 14 results for stakeholders'.

Don't

Do not update results silently — users relying on screen readers will have no indication that the list has changed.

Do

Return focus to the search input after the user clears the field with the Clear button.

Don't

Do not move focus to an unrelated element after clearing — it disorients keyboard and screen reader users.

Layout & Spacing

Input height: 24 / 32 / 40 / 48 / 56px (XS to XL), medium 40px, from --orbit-form-control-size-*-height. Add a 44px touch target around the smaller sizes. Shape: rectangular by default, or pill (--orbit-form-control-radius-pill). Horizontal padding inside input: 8 / 12 / 16 / 20 / 24px by size, --orbit-form-control-size-*-padding-inline Search icon size: 20x20px; gap between icon and text: --op-space-8 (8px) Clear button: 20x20px icon, right-aligned, margin-right --op-space-12 (12px) Label margin-bottom: --op-space-4 (4px) Suggestions dropdown: margin-top --op-space-4 (4px) from input bottom edge; border-radius --op-radius-md (8px); max-height 320px with overflow-y scroll Each suggestion item: padding --op-space-8 (8px) --op-space-12 (12px); min-height 44px Error message: margin-top --op-space-4 (4px); font-size --op-text-sm

Tokens

PartTokenValue
Input background --op-color-bg-primary White in light mode; dark surface in dark mode.
Input border (default) --op-color-border-default 1px solid border.
Input border (focus) --op-color-interactive-focus 3px focus ring, offset 2px.
Input text --op-color-text-primary Primary text colour for entered query.
Placeholder text --op-color-text-placeholder Subdued; must still meet 3:1 against input background.
Search icon --op-color-text-secondary Slightly subdued to avoid competing with input text.
Clear button icon --op-color-text-secondary Matches search icon; darkens to --op-color-text-primary on hover.
Suggestions dropdown background --op-color-bg-primary Matches input background for visual continuity.
Suggestions dropdown border --op-color-border-default 1px solid, same as input border.
Suggestion item (hover/focus) --op-color-bg-secondary Subtle highlight; do not use interactive green for hover backgrounds.
Suggestion item (selected/active) --op-color-interactive-default Green-400; white text on top. Used when an item is keyboard-activated.
Error border --op-color-status-error Replaces default border colour.
Error message text --op-color-status-error Paired with --op-color-status-error-bg for inline error banners if needed.
Disabled input --op-color-bg-disabled / --op-color-text-disabled Background and text both dimmed; pointer-events: none.

Engineering notes

  • The search container should be a <form role='search'> element (or a <div role='search'>) so screen reader users can navigate to it via landmark navigation.
  • Use aria-label on the form/container when there is no visible heading nearby — for example, aria-label='Stakeholder search'.
  • When suggestions are enabled, implement the ARIA combobox pattern: the input receives role='combobox', aria-expanded, aria-controls pointing to the listbox id, and aria-autocomplete='list'.
  • Each suggestion item should have role='option' and a unique id. Set aria-activedescendant on the input to match the currently highlighted option id.
  • Use a visually hidden aria-live='polite' region to announce result counts after debounce resolves — for example, 'Showing 8 results'.
  • The Clear button must have aria-label='Clear search' (or equivalent localised string) and type='button' to avoid submitting the form.
  • Apply @media (prefers-reduced-motion: reduce) to disable any suggestion dropdown animation transitions.
  • Debounce the input handler at 250ms before triggering async lookups. Cancel in-flight requests if a newer query supersedes them.
  • wa-input can be used as the base element; add the search icon via the prefix slot and the clear button via the suffix slot.

Keyboard interaction

KeyAction
Tab Moves focus into the search input from the preceding focusable element. If the suggestions dropdown is open, Tab closes it and moves focus to the next element outside the composite.
Shift+Tab Moves focus to the preceding focusable element. Closes suggestions dropdown if open.
Enter Submits the search query, or — if a suggestion is highlighted — selects that suggestion and populates the input.
Escape Closes the suggestions dropdown without selecting an option. Focus remains on the input.
Arrow Down Opens the suggestions dropdown (if closed and value is present) and moves highlight to the first option.
Arrow Up Moves highlight to the previous suggestion option. Wraps from first option back to the input.
Arrow Down / Arrow Up (in list) Moves highlight between suggestion options. Does not move DOM focus — aria-activedescendant tracks the highlighted option.
Home / End In the input field, moves cursor to start/end of text. If highlight is in the suggestions list, moves highlight to first/last option.

Why it matters

Government platforms serve users with a wide range of access needs, including screen reader users navigating by landmark and keyboard-only users who cannot use a mouse. Search is often a primary navigation mechanism — getting its semantics wrong (missing role='search', broken combobox pattern) can make entire record sets inaccessible.

Focus

Focus ring: 3px solid --op-color-interactive-focus, offset 2px, on the input element. The suggestions dropdown does not receive DOM focus — keyboard navigation through options is managed via aria-activedescendant on the input, keeping focus on the input at all times. After the Clear button is activated, focus is programmatically returned to the text input. When the suggestions dropdown closes (Escape or selection), focus remains on or returns to the text input.

ARIA

Role or attributeWhen to useExample
role='search' Applied to the wrapping <form> or <div> to expose the search landmark. <form role="search" aria-label="Stakeholder search">
role='combobox' Applied to the <input> when suggestions are enabled. <input type="search" role="combobox" aria-expanded="true" aria-controls="search-listbox" aria-autocomplete="list" />
aria-expanded On the combobox input. true when the suggestions dropdown is open, false when closed. aria-expanded="false"
aria-controls Points from the combobox input to the id of the suggestions listbox. aria-controls="search-suggestions"
aria-activedescendant Set to the id of the currently highlighted suggestion option. Empty string when no option is highlighted. aria-activedescendant="suggestion-3"
role='listbox' Applied to the suggestions dropdown container. <ul role="listbox" id="search-suggestions">
role='option' Applied to each item in the suggestions listbox. <li role="option" id="suggestion-1" aria-selected="false">Jane Smith</li>
aria-label (clear button) Provides an accessible name for the icon-only Clear button. <button type="button" aria-label="Clear search"><wa-icon name="x"></wa-icon></button>
aria-live='polite' On a visually hidden status region to announce result counts after search resolves. <div aria-live="polite" class="sr-only">Showing 14 results</div>

Contrast

Input text (--op-color-text-primary) against input background (--op-color-bg-primary): must meet 4.5:1 (WCAG AA for normal text). Placeholder text (--op-color-text-placeholder) against input background: minimum 3:1 (WCAG AA for UI components). Do not use placeholder as a label substitute even if contrast passes. Search icon (--op-color-text-secondary) against input background: minimum 3:1 as a UI component. Selected suggestion text (white) against --op-color-interactive-default (green-400): verify at implementation time — green-400 must achieve 4.5:1 against white. Swap to a darker green shade if it does not. Focus ring (--op-color-interactive-focus) against adjacent background: minimum 3:1 as a focus indicator.

Touch targets

The text input must be at least 44px tall in the default variant to meet the 44x44px minimum touch target. The Clear button icon must have a clickable/tappable area of at least 44x44px — use padding to extend the touch area without enlarging the visible icon. The compact variant (36px height) is restricted to mouse/keyboard desktop contexts only and must not appear on mobile viewports.

Things to avoid

  • Do not rely on placeholder text as the accessible label — always provide a <label> or aria-label.
  • Do not move DOM focus into the suggestions listbox — use aria-activedescendant on the input instead.
  • Do not auto-submit the search form on every keystroke — this causes unexpected page changes and disrupts screen reader users mid-input.
  • Do not suppress the focus ring in any state — some teams remove outlines for visual polish, which fails WCAG 2.4.7.
  • Do not use role='search' on an input element — apply it to the wrapping container (form or div) only.
  • Do not close the suggestions dropdown on blur without a delay — clicking a suggestion fires blur on the input before the click event; a short delay (150ms) prevents the list closing before the selection registers.

Was this page helpful?

Updated 2 October 2026