# Search Field

> A search box with the same sizes as Input. A clear button shows once there is text, Esc clears it, and an optional count says how many matched.

- Name: `search-field`
- Status: beta
- Categories: forms
- File: the install writes `search-field.tsx` to your `ui` alias, `@/components/ui` by default.
- Other registry items: `@arbokui/input`, `@arbokui/kbd`. The install adds them.
- Gallery: https://arbokui.com/components/search-field
- Registry item: https://arbokui.com/r/search-field.json

## Install

1. Add the registry to `components.json`. Do this first, once:

   ```bash
   npx shadcn@latest registry add "@arbokui=https://arbokui.com/r/{name}.json"
   ```

   The command writes this entry. You can also add it by hand:

   ```json
   {
     "registries": {
       "@arbokui": "https://arbokui.com/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@arbokui` in a public list that Arbokui does not control.

2. Add the theme once per app. It replaces your color tokens with ones checked for contrast:

   ```bash
   npx shadcn@latest add @arbokui/theme
   ```

3. Add the component:

   ```bash
   npx shadcn@latest add @arbokui/search-field
   ```

## Use it for

- Filtering a list or a table on the same page as people type.
- Give it a name: aria-label, like "Search people", or an id that a visible label's htmlFor points at.
- Pass count with the number of matches. It shows in the field, like "3 people" or "No people", and is announced politely. Set noun to the singular and plural words.
- Pass shortcut to focus the field from anywhere on the page: one key, like "/", or "Mod+K" for ⌘K on a Mac and Ctrl+K elsewhere. It shows as a quiet key at the end of the empty field, and hides once people type, on touch screens, and while disabled.
- Esc clears the text. With the field empty, Esc leaves it, and goes on to any dialog around it.
- Use onEnter to run a search that waits for Enter, like one that asks a server.

## Avoid it for

- Giving two parts on one page the same shortcut. Command Menu and Rail's onSearch listen for ⌘K too, so pass "Mod+K" only where neither is on the page.
- Picking one value from a list. Use a combobox.
- Using the placeholder as the name. It disappears as soon as people type.
- A search that opens a results page. A plain input in a form with a submit button works better there.

## Props

- `value`: `string`. The typed text. Use it with onValueChange.
- `defaultValue`: `string`. The text at first render, when you do not control it.
- `onValueChange`: `(value: string) => void`. Called with the new text on every change, and with "" when cleared.
- `onEnter`: `(value: string) => void`. Called with the text when Enter is pressed.
- `size`: `"sm" | "md" | "lg"`. Default `"md"`. Height, padding, and text size. The same heights as Input.
- `count`: `number | null`. How many matched. Shows in the field and is announced. Hidden while the field is empty.
- `noun`: `[string, string]`. Default `["match", "matches"]`. The singular and plural words for the count.
- `shortcut`: `string`. Focuses the field from anywhere. One key, like "/", is ignored while people type in another field. "Mod+" and one key, like "Mod+K", is ⌘K on a Mac and Ctrl+K elsewhere, and works from another field too, but not in a rich text editor. Shows as a ghost Kbd while the field is empty, with a letter in capitals, as the keyboard prints it.
- `disabled`: `boolean`. Default `false`. Blocks typing and hides the clear button.
- `placeholder`: `string`. A hint inside the empty field, like "Search people".
- `aria-label`: `string`. Names the field. Required unless you pass aria-labelledby, or an id with a visible label.
- `className`: `string`. Classes for the field's box. Other props, like name and id, land on the input.

## Accessibility

- A native input with type="search", so screen readers call it a search field.
- Its type needs a name: aria-label, aria-labelledby, or an id for a label's htmlFor.
- The count sits in a polite live region, so a new count is read out without moving focus.
- Esc clears the text first, and marks the field data-owns-escape while it has text. A dialog around it closes only on the next Esc.
- The clear button has the name "Clear search". It is not a Tab stop, since Esc does the same from the keyboard. It is at least 24px square, and 44px on a coarse pointer.
- shortcut sets aria-keyshortcuts, so screen readers can say the key. "Mod+K" sets "Meta+K Control+K". The printed key is aria-hidden, so it is not read twice.
- On touch screens the text is 16px, so iOS Safari does not zoom in when the field gets focus.

## Examples

### Jump in with ⌘K

```tsx
<SearchField aria-label="Search the app" placeholder="Search" shortcut="Mod+K" />
```

### Filter a list

```tsx
const people = ["Dan Kerr", "Maya Patel", "Tom Hale"];
const [query, setQuery] = useState("");
const shown = people.filter((name) => name.toLowerCase().includes(query.toLowerCase()));

<SearchField
  aria-label="Search people"
  placeholder="Search people"
  value={query}
  onValueChange={setQuery}
  count={shown.length}
  noun={["person", "people"]}
  shortcut="/"
/>
```

### Small, in a toolbar

```tsx
<SearchField size="sm" aria-label="Search matches" placeholder="Search" />
```
