# Expandable Search

A collapsed icon trigger that expands into a search input on click.

## Installation

```tsx
import { ExpandableSearch } from "@makeplane/propel/components/expandable-search";
```
## Usage

```tsx
import { ExpandableSearch } from "@makeplane/propel/components/expandable-search";

export default function BasicDemo() {
  return <ExpandableSearch aria-label="Search" clearLabel="Clear search" size="lg" />;
}
```
## Examples

### With suggestions

Pass `items` and `AutocompleteContent` (same anatomy as [Autocomplete](/components/autocomplete))
to turn the expanded input into a filterable search box. Without them, the popup stays forced
closed and it's a plain search box.

```tsx
import {
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteItem,
  AutocompleteList,
} from "@makeplane/propel/components/autocomplete";
import { ExpandableSearch } from "@makeplane/propel/components/expandable-search";

const IMAGES = ["nginx:1.29-alpine", "node:22-slim", "postgres:18", "redis:8.2.2-alpine"];

export default function WithSuggestionsDemo() {
  return (
    <ExpandableSearch
      aria-label="Search images"
      clearLabel="Clear search"
      size="lg"
      items={IMAGES}
      mode="both"
    >
      <AutocompleteContent>
        <AutocompleteEmpty>No matches</AutocompleteEmpty>
        <AutocompleteList>
          {(image: string) => (
            <AutocompleteItem key={image} value={image} size="md">
              {image}
            </AutocompleteItem>
          )}
        </AutocompleteList>
      </AutocompleteContent>
    </ExpandableSearch>
  );
}
```

### Sizes

`size` steps the collapsed trigger and expanded input row together (`md`, `lg`, `xl`, `2xl`). The
inner icon buttons sit one ladder rung below the row.

```tsx
import { type AutocompleteSize } from "@makeplane/propel/components/autocomplete";
import { ExpandableSearch } from "@makeplane/propel/components/expandable-search";

const SIZES: AutocompleteSize[] = ["md", "lg", "xl", "2xl"];

export default function SizesDemo() {
  return (
    <div className="flex flex-col gap-3">
      {SIZES.map((size) => (
        <ExpandableSearch
          key={size}
          aria-label={`Search ${size}`}
          clearLabel="Clear search"
          size={size}
        />
      ))}
    </div>
  );
}
```
## API Reference

### ExpandableSearch

A collapsed icon trigger that expands into a search input on click, collapsing again on blur or
Escape while empty — unless it's `required` and still invalid, in which case it stays expanded so
the field remains focusable instead of collapsing back into an inert trigger. Escape restores
focus to the trigger. Expand is controllable via `expanded`/`defaultExpanded`/`onExpandedChange`
(separate from Autocomplete's popup `open`). Built on `Autocomplete` — pass `items` and
`children` (e.g. `AutocompleteContent`) for suggestions, or omit both for a plain search box.
Without `children` the popup is forced closed (no listbox ever mounts), so a plain search box
never claims `aria-expanded`. Non-empty `value`/`defaultValue` starts expanded (and controlled
non-empty `value` keeps it expanded); a controlled `open` is forced closed while collapsed so a
popup never mounts over an inert input. The `Autocomplete` root and its input stay mounted at
every state — the trigger/row swap width via an animated CSS grid track and `inert` instead of
unmounting or `hidden` — so a `required`/`defaultValue` input keeps working under native form
validation and keeps its own state across collapse/expand instead of resetting.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `aria-label` (required) | `string` | — | Accessible name applied to both the collapsed trigger and the expanded input. |
| `clearLabel` (required) | `string` | — | Accessible name for the clear button shown once the input has a value. Localizable. |
| `size` (required) | `"md" \| "lg" \| "xl" \| "2xl"` | — | Size, shared by the collapsed trigger and the expanded input row (same scale as `Autocomplete`). The trigger/clear `IconButton`s step one ladder rung below it (see `ICON_BUTTON_SIZE`), so the collapsed icon reads as a smaller control inside the expanded row's own box — `ExpandableSearchTrigger` pads that box up to the row's height at the same step, so toggling between them never shifts height. |
| `items` | `readonly Value[] \| (readonly Group<Value>[] & readonly Value[])` | — | The items to be displayed in the list. Can be either a flat array of items or an array of groups with items. Nullish entries are not supported: remove them from the data before passing it. Items to display in the autocomplete list. |
| `placeholder` | `string` | `Search…` | Input placeholder shown once expanded. |
| `expanded` | `boolean` | — | Controlled expand state. When set, the trigger/row visibility is driven by the consumer (e.g. a `/` shortcut). Pair with `onExpandedChange`. Distinct from Autocomplete's `open` (popup). |
| `defaultExpanded` | `boolean` | — | Uncontrolled initial expand state. Defaults to expanded when `value`/`defaultValue` is non-empty so a pre-filled search is not trapped under an inert trigger. |
| `onExpandedChange` | `((expanded: boolean) => void)` | — | Called when expand state changes, in both controlled and uncontrolled mode. |
| `children` | `ReactNode` | — | Popup content (e.g. `AutocompleteContent`) shown once expanded, when `items` are provided. |
