<!-- Protocore Design System — SearchInput -->
# SearchInput

- **Category:** Inputs (`inputs`)
- **Slug:** `inputs/search-input`
- **Status:** stable
- **Platforms:** web
- **Import:** `import { SearchInput } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/inputs/search-input

> An Input specialised for queries — leading magnifier, sunken field, and a clear button once text is present.

## When to use

Use **SearchInput** for free-text filtering over a set you already show — a table, a list, a grid of nodes. It's a presentation-level query box: you own the matching logic.

- Need type-ahead that *selects* one item from a list of options? Use **Combobox**.
- Building an app-wide, keyboard-summoned launcher (⌘K)? Use **CommandPalette**.
- Assembling several filters (chips, selects) plus a query? Compose SearchInput inside a **FilterBar**.

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `className` | `string` | no | — | — |
| `defaultValue` | `string` | no | — | Initial query value when uncontrolled. |
| `invalid` | `boolean` | no | — | Mark the field invalid — danger border plus `aria-invalid`. |
| `onValueChange` | `((value: string) => void)` | no | — | Fires with the new query string on every edit and when cleared. |
| `size` | `enum` | no | — | Control height: `sm` (32) · `md` (36, default) · `lg` (40). |
| `style` | `CSSProperties` | no | — | — |
| `value` | `string` | no | — | Controlled query value. |

## Examples

### Basics

A query field built on Input: it carries a leading magnifier, reports edits through `onValueChange`, and reveals a clear × once there's text. Works uncontrolled with `defaultValue`.

```tsx
import { SearchInput } from "@protocore/pds";

export default function Basics() {
  // Leading magnifier plus a clear button that appears once text is present.
  return <SearchInput placeholder="Search nodes…" style={{ maxWidth: 320 }} />;
}
```

### Controlled filter

The everyday use: control `value`, filter a list on every keystroke, and let the built-in clear button reset the query. Clearing also fires `onValueChange("")` and refocuses the field.

```tsx
import { SearchInput } from "@protocore/pds";
import { useState } from "react";

const NODES = ["eu-central-1", "eu-central-3", "us-east-1", "ap-south-2", "sa-east-1"];

export default function ControlledFilter() {
  const [query, setQuery] = useState("");
  const matches = NODES.filter((node) => node.includes(query.toLowerCase()));

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12, maxWidth: 320 }}>
      <SearchInput value={query} onValueChange={setQuery} placeholder="Filter nodes…" />
      <ul style={{ margin: 0, paddingLeft: 18, font: "13px/1.7 monospace" }}>
        {matches.map((node) => (
          <li key={node}>{node}</li>
        ))}
        {matches.length === 0 && <li style={{ listStyle: "none", opacity: 0.6 }}>No matches</li>}
      </ul>
    </div>
  );
}
```

## Do & don't

**Do**

- Use it to filter content that's already on screen.
- Debounce expensive queries in your onValueChange handler.
- Let the built-in clear button reset the query rather than adding your own.
- Give it a descriptive placeholder ("Filter nodes…").

**Don't**

- Don't use SearchInput to pick one option from a set — that's Combobox.
- Don't reimplement the magnifier or clear affordance; they're built in.
- Don't pass startAdornment/endAdornment — the specialisation owns those slots.
- Don't treat it as a global launcher; that's CommandPalette.

## Accessibility

**Keyboard**

| Keys | Action |
| --- | --- |
| `Type` | Update the query; fires onValueChange on each edit. |
| `Tab` | Move focus to the clear button once text is present. |
| `Enter / Space (on ×)` | Clear the query and refocus the field. |

**Notes**

- Renders a `type="search"` input with `role="searchbox"`.
- The clear button is labelled "Clear search" and only appears when there's text.
- Controlled via `value` + `onValueChange`; uncontrolled via `defaultValue`.
- When `disabled`, the clear button is removed from the tab order.

## Related

`input`, `combobox`, `command-palette`, `filter-bar`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
