SearchField
Search input with a built-in dense clear button.
import { SearchField } from '@elirobinson/react/components/molecules/SearchField';Styles: @elirobinson/react/styles/molecules/SearchField.css — already included when you import @elirobinson/react/styles.css.
Show code
import { SearchField } from '@elirobinson/react/components/molecules/SearchField';
export default function Basic() {
return <SearchField aria-label="Search coaching guides" defaultValue="practice plan" />;
}When to use it
Use SearchField for an inline filter — a table toolbar, a list you want to narrow as
you type. It's an <input type="search"> with a built-in clear button, nothing more. For
filtering that also opens a list of matching options to pick from, use Combobox
instead; SearchField never renders a popup.
Like Input, it supports both patterns: pass value/onValueChange to drive it from
your own state (as in the filtering example below), or defaultValue and let it manage
its own state uncontrolled.
Controlled, filtering a list
- Weeknight Pasta
- Sheet-Pan Chicken
- Ten-Minute Tacos
- Fridge Soup
Show code
import { useState } from 'react';
import { SearchField } from '@elirobinson/react/components/molecules/SearchField';
const RECIPES = ['Weeknight Pasta', 'Sheet-Pan Chicken', 'Ten-Minute Tacos', 'Fridge Soup'];
export default function Controlled() {
const [query, setQuery] = useState('');
const results = RECIPES.filter((recipe) => recipe.toLowerCase().includes(query.toLowerCase()));
return (
<div className="demo-col">
<SearchField aria-label="Search recipes" value={query} onValueChange={setQuery} />
<ul>
{results.length > 0 ? (
results.map((recipe) => <li key={recipe}>{recipe}</li>)
) : (
<li>No recipes match "{query}".</li>
)}
</ul>
</div>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | string | — | — |
onValueChange | ((value: string) => void) | — | — |
value | string | — | — |
Also accepts all Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange' | 'value' | 'defaultValue'> props.
Accessibility
SearchFielddoesn't render its own<label>— unlikeInput, it has nolabelprop. Give it an accessible name yourself witharia-label(as every demo on this page does) oraria-labelledby, or wrap it inFormFieldif you want a visible label plus hint/error text.- The underlying element is a native
<input type="search">, which browsers and screen readers expose with thesearchboxrole automatically. - The clear button only renders once there's a value, carries
aria-label="Clear search", and returns focus to the input after clearing — so clearing never strands keyboard focus. - The clear button follows dense inline sizing (MUI/shadcn scale), not the 44px primary-control minimum.
- Keyboard: standard text-input behavior — type to filter,
Tabreaches the clear button when it's present,Enter/Spaceactivates it. There's noEscape-to-clear shortcut wired in. - The ref forwards to the real
<input>element, not the wrapping<div>— callingref.current.focus()works directly.ComboboxandCommandPaletteboth depend on this.
Do
- Always give it an aria-label or aria-labelledby — it has no visible label of its own.
- Debounce the filtering logic in onValueChange for anything more expensive than an in-memory array filter.
- Show a "no results" message in the list below rather than leaving it silently empty.
- Use defaultValue for a simple, self-contained search box that doesn't need to sync with other state.
Don't
- Wrap Input inside FormField expecting SearchField-like behavior — they're different components with different label handling.
- Expect a popup of matching options — that's Combobox, not SearchField.
- Rely on Escape to clear the field; wire your own keydown handler if you want that.
- Forget the clear button's dense hit area when laying out tight toolbar spacing — verify it doesn't overlap adjacent controls.