Search Box
A search field with a search icon and a clear button. Two sizes, three fills and every state.
Version 0.4.1 ·
Installation
bunx --bun shadcn@latest add @dga/search-boxUsage
import { useState } from "react";
import { Field, FieldLabel } from "@/components/ui/field";
import { SearchBox } from "@/components/ui/search-box";
export function ServiceSearch() {
const [query, setQuery] = useState("");
return (
<Field>
<FieldLabel>Search services</FieldLabel>
<SearchBox
value={query}
onValueChange={setQuery}
placeholder="Search services"
clearLabel="Clear search"
/>
</Field>
);
}Use Search Box for finding things in a list, a table or the whole site. Give it a visible label or an aria-label, and a placeholder that says what is searched. Translate clearLabel on Arabic pages. Search results are your own: this component only collects the query.
Anatomy
- Box: the same border and fill as Input.
- Search icon: on the start side, decorative.
- Input (
type="search"): the query. - Clear button: on the end side, shown when there is text.
Examples
Clear button
Type to show the clear button. It empties the field, returns focus to it and calls onValueChange with an empty string. Esc does the same.
States
Default, filled with the clear button, read-only, disabled, and the medium size with a darker fill.
RTL
The search icon is on the right (start) and the clear button on the left (end). The icons are not directional, so they are not flipped. Arabic placeholders and queries align right.
Accessibility
| Key | Action |
|---|---|
| Tab | Moves focus to the field, then to the clear button when there is text. |
| Esc | Clears the text. |
| Enter | Submits the form it is in. |
- A native
type="search"input, announced as a search field. - The clear button has an accessible name (
clearLabel), a 24px target and its own focus ring. - Put the field in a
<form role="search">or asearchlandmark so people can jump to it. - Announce the number of results in a live region (
role="status") when they update.
API Reference
SearchBox
A search field with a search icon on the start side and a clear button on the end side that appears once there is text. It is `type="search"`, so Escape clears it too.
| Prop | Type | Default |
|---|---|---|
"md" | "lg"Height: `md` 32px, `lg` 40px. | No default | |
| ||
(value: string) => voidCalled with the new text whenever it changes, including when it is cleared. | No default | |
| ||
"default" | "lighter" | "darker"Fill style. `lighter` and `darker` keep the border. | No default | |
| ||
stringThe value of the input. Use when controlled. | No default | |
| ||
stringAccessible name of the clear button. Translate it on Arabic pages. | "Clear search" | |
| ||
stringClass names for the native `<input>`. `className` styles the box around it. | No default | |
| ||
stringThe default value of the input. Use when uncontrolled. | No default | |
| ||
booleanDisables the field. | No default | |
| ||
booleanThe text can be read but not changed. The clear button is hidden. | No default | |
| ||
stringHint shown while empty. | No default | |
| ||
Also accepts every prop of the Base UI Input (opens in a new tab).
Deviations from DGA
- Figma's trailing icon variant (clear or voice) is a real clear button with a name, and returns focus to the field.
- States follow Input: no outline, a centre-out underline, and lighter and darker without a border at rest.
| Change | Reason |
|---|---|
Search Box: clear button | Icon-only controls need a name and a keyboard path. |
Contrast
282 pairs checked · all pass WCAG 2.1 AAShow 47 statesHide
| Variant / state | Light | Dark |
|---|---|---|
| filled text | 18.09:1 AAA | 15.87:1 AAA |
| hovered text | 18.09:1 AAA | 15.87:1 AAA |
| focused text | 10.17:1 AAA | 12.04:1 AAA |
| pressed text | 9.24:1 AAA | 9.64:1 AAA |
| pressed placeholder | 6.69:1 AA | 5.06:1 AA |
| pressed prefix and suffix text | 9.24:1 AAA | 9.64:1 AAA |
| underline, focused and pressed | 18.74:1 3:1 | 16.80:1 3:1 |
| placeholder | 4.77:1 AA | 6.32:1 AA |
| prefix and suffix text | 10.17:1 AAA | 12.04:1 AAA |
| icon | 4.77:1 3:1 | 9.38:1 3:1 |
| border, default | 4.57:1 3:1 | 3.80:1 3:1 |
| border, hovered | 9.73:1 3:1 | 12.04:1 3:1 |
| border, focused and pressed | 17.93:1 3:1 | 16.80:1 3:1 |
| underline, error | 4.62:1 3:1 | 4.65:1 3:1 |
| border, error | 4.62:1 3:1 | 4.65:1 3:1 |
| filled text (lighter) | 17.64:1 AAA | 14.42:1 AAA |
| hovered text (lighter) | 17.64:1 AAA | 14.42:1 AAA |
| focused text (lighter) | 10.17:1 AAA | 12.04:1 AAA |
| pressed text (lighter) | 9.24:1 AAA | 9.64:1 AAA |
| pressed placeholder (lighter) | 6.69:1 AA | 5.06:1 AA |
| pressed prefix and suffix text (lighter) | 9.24:1 AAA | 9.64:1 AAA |
| underline, focused and pressed (lighter) | 18.28:1 3:1 | 15.27:1 3:1 |
| placeholder (lighter) | 4.65:1 AA | 5.75:1 AA |
| prefix and suffix text (lighter) | 9.92:1 AAA | 10.95:1 AAA |
| icon (lighter) | 4.65:1 3:1 | 8.52:1 3:1 |
| border, hovered (lighter) | 9.73:1 3:1 | 12.04:1 3:1 |
| border, focused and pressed (lighter) | 17.93:1 3:1 | 16.80:1 3:1 |
| underline, error (lighter) | 4.62:1 3:1 | 4.65:1 3:1 |
| border, error (lighter) | 4.62:1 3:1 | 4.65:1 3:1 |
| filled text (darker) | 16.44:1 AAA | 17.04:1 AAA |
| hovered text (darker) | 16.44:1 AAA | 17.04:1 AAA |
| focused text (darker) | 10.17:1 AAA | 12.04:1 AAA |
| pressed text (darker) | 9.24:1 AAA | 9.64:1 AAA |
| pressed placeholder (darker) | 6.69:1 AA | 5.06:1 AA |
| pressed prefix and suffix text (darker) | 9.24:1 AAA | 9.64:1 AAA |
| underline, focused and pressed (darker) | 17.03:1 3:1 | 18.03:1 3:1 |
| placeholder (darker) | 6.69:1 AA | 6.79:1 AA |
| prefix and suffix text (darker) | 9.24:1 AAA | 12.93:1 AAA |
| icon (darker) | 4.34:1 3:1 | 10.07:1 3:1 |
| border, hovered (darker) | 9.73:1 3:1 | 12.04:1 3:1 |
| border, focused and pressed (darker) | 17.93:1 3:1 | 16.80:1 3:1 |
| underline, error (darker) | 4.62:1 3:1 | 4.65:1 3:1 |
| border, error (darker) | 4.62:1 3:1 | 4.65:1 3:1 |
| border, hover and focus (lighter and darker) | 4.57:1 3:1 | 3.80:1 3:1 |
| read-only text | 18.09:1 AAA | 15.87:1 AAA |
| clear button icon | 4.77:1 3:1 | 9.38:1 3:1 |
| clear button icon, hovered | 16.44:1 3:1 | 12.71:1 3:1 |
Text needs 4.5:1, icons and focus rings 3:1. Disabled states are exempt. Full contrast report