Primitives
Search
A role='searchbox' text input that mirrors its value to a signal and reflects validation state, paired with a clear button that self-hides while the field is empty. Reuses forInput's form-value wiring, so it auto-wires with Signal Forms and Field.
Type in the box and clear it again. The clear button is yours to render, and the host reflects data-empty for as long as there is nothing to clear.
- Accordion
- Breadcrumbs
- Combobox
- Date Picker
- Dialog
- File Upload
- Listbox
- Pagination
- Popover
- Slider
- Switch
- Tooltip
[forSearch] applies on a native <input>, wires its value to a signal, reflects validation state, and exposes a clear() / focusInput() API for the companion [forSearchClear] clear button.
Anatomy
<div forSearchGroup>
<input forSearch [(value)]="query" placeholder="Search…" />
<button forSearchClear ariaLabel="Clear search">×</button>
</div>
[forSearchClear] self-hides while the value is empty and refocuses the input
on activation. Wrap the field and the button in a [forSearchGroup] so the
button can coordinate with the field. The void <input> can't contain the
button as a DOM descendant, so they bridge through the group registry. A
standalone [forSearch] (no clear button) needs no group.
Examples
Inside a Field with Signal Forms
forSearch implements FormValueControl<string>, so [formField] auto-wires it inside forField exactly like forInput: the label adopts the control id, validation flows into aria-errormessage, and aria-invalid / aria-required are reflected. Type one or two characters and blur to surface the error.
With Signal Forms and Field
<div forField>
<label forLabel>Search</label>
<input forSearch [formField]="searchForm.query" />
</div>
[formField] auto-wires the FormValueControl<string> contract: required,
invalid, touched, and the value itself flow in and out without extra glue.
Command palette
@if (paletteOpen()) {
<div forDialog ariaLabel="Command palette" (dismiss)="paletteOpen.set(false)">
<input forSearch [(value)]="query" [clearOnEscape]="false" placeholder="Type a command…" />
<!-- results… -->
</div>
}
When the search box is the overlay's only content, [clearOnEscape]="false"
makes the first Escape dismiss the palette instead of clearing the query
first (see Keyboard below).
API
ForSearch
Applied to a native <input>. Sets role="searchbox", mirrors the value to a
signal, reflects validation state, and exposes clear() / focusInput() for
the companion clear button. Implements FormValueControl<string>, so it
auto-wires with [formField] and auto-associates inside a [forField].
clear() is a no-op while the field is disabled or read-only, whichever caller
invokes it: the clear button, the Escape key, or your own code through the
[forSearchGroup] context.
| Input | Type | Default | Description |
|---|---|---|---|
clearOnEscape | boolean | true | Whether Escape clears a non-empty value before propagating. Set to false for command-palette compositions. |
| Data attribute | Values | |
|---|---|---|
data-disabled | present when the field is disabled | |
data-readonly | present when the field is read-only | |
data-empty | present while the value is '' (empty) |
ForSearchGroup
Optional coordination wrapper. Renders nothing and imposes no role or layout;
it bridges the [forSearchClear] button to the [forSearch] field through a
registry, since the void <input> can't contain the button as a descendant.
Required only when you use the clear button.
ForSearchClear
Clear button. Apply on a <button> inside a [forSearchGroup] that also wraps
the [forSearch]. No instance is passed through the template. Self-hides while
the value is empty and refocuses the input on activation.
| Input | Type | Default | Description |
|---|---|---|---|
ariaLabel | string | null | scope clearAriaLabel ('Clear') | Accessible name for the icon-only button. Set to null to drop the attribute. |
Keyboard
| Key | Behaviour | |
|---|---|---|
Escape | Clears a non-empty value, matching the native <input type="search"> affordance. |
Escape is consumed (preventDefault() + stopPropagation()) only when it
clears. When the field is already empty (or disabled / read-only, where
clearing is a no-op), the key is left to propagate, so a [forSearch] placed
inside a Dialog, Popover, or Combobox panel does not swallow that overlay's own
Escape dismissal. A non-empty search box inside an overlay therefore takes two
presses: the first clears the field, the second closes the overlay.
That is the right default for a searchbox alongside other content, and the wrong
one for a command palette, where the search box is the dialog's only content
and one Escape should close it. Opt out with [clearOnEscape]="false": the
directive then neither acts on nor consumes Escape, so the enclosing
dismissible layer sees it on the first press even with a non-empty query.
<input forSearch [(value)]="query" [clearOnEscape]="false" />
The propagation rule for an empty, disabled, or read-only field is unchanged:
Escape passes through untouched in all three cases regardless of
clearOnEscape.
Accessibility
The
role="searchbox"attribute is set statically by the directive.Validation state (
aria-required,aria-invalid,aria-readonly) is reflected as truthy-only attributes (absent whenfalse). The disabled state reflects through the nativedisabledattribute alone (noaria-disabled), so style it with:disabledor[data-disabled].[forSearchClear]carriesaria-label="Clear"by default so the icon-only button has an accessible name. Override it per-instance with[ariaLabel], or centrally (and for localization) withprovideForSearchDefaults:providers: [provideForSearchDefaults({ clearAriaLabel: 'Limpiar' })];Set
[ariaLabel]="null"to drop the attribute entirely.