# Autocomplete (/ui/components/react/autocomplete)




## Usage [#usage]

```tsx
import {
  Autocomplete,
  AutocompleteInput,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteList,
  AutocompleteItem,
} from '@appica/ui-react/autocomplete'
```

```tsx
const frameworks = ['Next.js', 'Remix', 'Astro', 'Nuxt.js', 'SvelteKit', 'SolidStart']

<Autocomplete items={frameworks}>
  <AutocompleteInput placeholder="Search a framework" />
  <AutocompleteContent>
    <AutocompleteEmpty>No frameworks found.</AutocompleteEmpty>
    <AutocompleteList>
      {(item) => (
        <AutocompleteItem key={item} value={item}>
          {item}
        </AutocompleteItem>
      )}
    </AutocompleteList>
  </AutocompleteContent>
</Autocomplete>
```

`Autocomplete` is a compound component. The root holds the data (`items`) and shared options (`size`, `variant`, `clearable`, `icon`); the parts compose the input and the filtered popup:

* **`AutocompleteInput`** - the text field, styled like [`Input`](/ui/components/react/input). Add a clear button with `clearable` and a dropdown chevron with `icon` (both on the root, both off by default).
* **`AutocompleteContent`** - the portalled, auto-positioned popup. Accepts the shared [floating props](/ui/components/react/popover) (`side`, `align`, `sideOffset`, …).
* **`AutocompleteList`** - the scrollable list. Pass a render function to map over the filtered items, or static `AutocompleteItem`s.
* **`AutocompleteItem`** - one option; its `value` is what selection reports.
* **`AutocompleteEmpty`** - shown only when the filter matches nothing.

### Reaching the positioner [#reaching-the-positioner]

`AutocompleteContent` is the popup, so its `className` styles the popup. The elements around it have their own escape hatches: `positionerProps` for the element that places it and `portalProps` for the portal. The positioning props you reach for most - `side`, `align`, `sideOffset`, `anchor`, the collision props - are already flat props on `AutocompleteContent`.

The common reason to use one is theming. A popup portals to `<body>`, so CSS inheritance stops at that boundary and a popup opened from inside a scoped dark region renders light. Putting the class on the positioner fixes it, because the class only has to land on some ancestor of the popup:

```tsx
<AutocompleteContent positionerProps={{ className: 'dark' }}>…</AutocompleteContent>
```

The flat `container` prop moves the portal target itself. It's for shadow DOM and iframes, not theming - see [Dark Mode](/ui/docs/react/dark-mode#scoped-dark-regions-and-portals) and [Composition](/ui/docs/react/composition#portals-and-the-container-prop).

## Examples [#examples]

### Variants [#variants]

`variant` switches the input appearance between a bordered `outline` (default) and a filled `soft` field.

```tsx
'use client'

import {
  Autocomplete,
  AutocompleteInput,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteList,
  AutocompleteItem,
} from '@appica/ui-react/autocomplete'

const frameworks = ['Next.js', 'Remix', 'Astro', 'Nuxt.js', 'SvelteKit', 'SolidStart', 'Gatsby', 'Vite']
const variants = ['outline', 'soft'] as const

export default function AutocompleteVariants() {
  return (
    <div className="flex w-full max-w-70 flex-col gap-4">
      {variants.map((variant) => (
        <div key={variant}>
          <Autocomplete items={frameworks} variant={variant}>
            <AutocompleteInput placeholder="Search a framework" aria-label={`Search (${variant})`} />
            <AutocompleteContent>
              <AutocompleteEmpty>No frameworks found.</AutocompleteEmpty>
              <AutocompleteList>
                {(item: string) => (
                  <AutocompleteItem key={item} value={item}>
                    {item}
                  </AutocompleteItem>
                )}
              </AutocompleteList>
            </AutocompleteContent>
          </Autocomplete>
        </div>
      ))}
    </div>
  )
}
```

### Sizes [#sizes]

`size` on the root scales the input, popup radius, and items together.

```tsx
'use client'

import {
  Autocomplete,
  AutocompleteInput,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteList,
  AutocompleteItem,
} from '@appica/ui-react/autocomplete'

const frameworks = ['Next.js', 'Remix', 'Astro', 'Nuxt.js', 'SvelteKit', 'SolidStart', 'Gatsby', 'Vite']
const sizes = ['sm', 'md', 'lg'] as const

export default function AutocompleteSizes() {
  return (
    <div className="flex w-full max-w-70 flex-col gap-4">
      {sizes.map((size) => (
        <div key={size}>
          <Autocomplete items={frameworks} size={size}>
            <AutocompleteInput placeholder="Search a framework" aria-label={`Search (${size})`} />
            <AutocompleteContent>
              <AutocompleteEmpty>No frameworks found.</AutocompleteEmpty>
              <AutocompleteList>
                {(item: string) => (
                  <AutocompleteItem key={item} value={item}>
                    {item}
                  </AutocompleteItem>
                )}
              </AutocompleteList>
            </AutocompleteContent>
          </Autocomplete>
        </div>
      ))}
    </div>
  )
}
```

### Clearable & chevron [#clearable--chevron]

Set `clearable` to add a clear (✕) button once there's a value, and `icon` to add a chevron that toggles the popup. Both render inside the input and are off by default.

```tsx
'use client'

import {
  Autocomplete,
  AutocompleteInput,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteList,
  AutocompleteItem,
} from '@appica/ui-react/autocomplete'

const frameworks = ['Next.js', 'Remix', 'Astro', 'Nuxt.js', 'SvelteKit', 'SolidStart', 'Gatsby', 'Vite']

export default function AutocompleteClearable() {
  return (
    <div className="w-full max-w-70">
      <Autocomplete items={frameworks} defaultValue="Next.js" clearable icon>
        <AutocompleteInput placeholder="Search a framework" aria-label="Search a framework" />
        <AutocompleteContent>
          <AutocompleteEmpty>No frameworks found.</AutocompleteEmpty>
          <AutocompleteList>
            {(item: string) => (
              <AutocompleteItem key={item} value={item}>
                {item}
              </AutocompleteItem>
            )}
          </AutocompleteList>
        </AutocompleteContent>
      </Autocomplete>
    </div>
  )
}
```

### Items with icons [#items-with-icons]

Items can render any content. Mark a leading [icon](/ui/icons) with `data-icon="start"` so it gets the same inner spacing as in [`Button`](/ui/components/react/button). When `items` are objects rather than strings, give the root an `itemToStringValue` so the filter and input know how to read each one. Here the selected command's icon is mirrored back into the input via `AutocompleteInput`'s `startSlot`.

```tsx
'use client'

import * as React from 'react'
import {
  Autocomplete,
  AutocompleteInput,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteList,
  AutocompleteItem,
} from '@appica/ui-react/autocomplete'
import { LayoutDashboard, User, Settings, CreditCard, Bell, Mail } from '@appica/icons-react'

interface Command {
  label: string
  icon: React.ElementType
}

const commands: Command[] = [
  { label: 'Dashboard', icon: LayoutDashboard },
  { label: 'Profile', icon: User },
  { label: 'Settings', icon: Settings },
  { label: 'Billing', icon: CreditCard },
  { label: 'Notifications', icon: Bell },
  { label: 'Messages', icon: Mail },
]

export default function AutocompleteWithIcons() {
  const [value, setValue] = React.useState('')
  const selected = commands.find((command) => command.label === value)

  return (
    <div className="w-full max-w-70">
      <Autocomplete
        items={commands}
        value={value}
        onValueChange={(v: string) => setValue(v)}
        itemToStringValue={(item) => (item as Command).label}
        clearable
        icon
      >
        <AutocompleteInput
          placeholder="Search commands"
          aria-label="Search commands"
          startSlot={selected ? <selected.icon aria-hidden /> : null}
        />
        <AutocompleteContent>
          <AutocompleteEmpty>No commands found.</AutocompleteEmpty>
          <AutocompleteList>
            {(command: Command) => (
              <AutocompleteItem key={command.label} value={command}>
                <command.icon data-icon="start" />
                {command.label}
              </AutocompleteItem>
            )}
          </AutocompleteList>
        </AutocompleteContent>
      </Autocomplete>
    </div>
  )
}
```

### Country search [#country-search]

The same object-item pattern with [country flags](/ui/country-flags) - a typical country picker. Each item renders a flag before the name, and the selected country's flag is mirrored into the input through `startSlot`.

```tsx
'use client'

import * as React from 'react'
import {
  Autocomplete,
  AutocompleteInput,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteList,
  AutocompleteItem,
} from '@appica/ui-react/autocomplete'
import { CountryFlagRounded } from '@appica/country-flags-react'

interface Country {
  code: string
  name: string
}

const countries: Country[] = [
  { code: 'au', name: 'Australia' },
  { code: 'br', name: 'Brazil' },
  { code: 'ca', name: 'Canada' },
  { code: 'fr', name: 'France' },
  { code: 'de', name: 'Germany' },
  { code: 'it', name: 'Italy' },
  { code: 'jp', name: 'Japan' },
  { code: 'es', name: 'Spain' },
  { code: 'gb', name: 'United Kingdom' },
  { code: 'us', name: 'United States' },
]

export default function AutocompleteCountrySearch() {
  const [value, setValue] = React.useState('')
  const selected = countries.find((country) => country.name === value)

  return (
    <div className="w-full max-w-70">
      <Autocomplete
        items={countries}
        value={value}
        onValueChange={(v: string) => setValue(v)}
        itemToStringValue={(item) => (item as Country).name}
        clearable
        icon
      >
        <AutocompleteInput
          placeholder="Search a country"
          aria-label="Search a country"
          startSlot={selected ? <CountryFlagRounded code={selected.code} aria-hidden /> : null}
        />
        <AutocompleteContent>
          <AutocompleteEmpty>No countries found.</AutocompleteEmpty>
          <AutocompleteList>
            {(country: Country) => (
              <AutocompleteItem key={country.code} value={country}>
                <CountryFlagRounded code={country.code} data-icon="start" aria-hidden />
                {country.name}
              </AutocompleteItem>
            )}
          </AutocompleteList>
        </AutocompleteContent>
      </Autocomplete>
    </div>
  )
}
```

### Grouped options [#grouped-options]

Pass a grouped `items` array (`{ value, items }[]`) and render each group with `AutocompleteGroup` + `AutocompleteLabel` + `AutocompleteCollection`. The outer render function iterates groups; `AutocompleteCollection` renders the items inside each.

```tsx
'use client'

import {
  Autocomplete,
  AutocompleteInput,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteList,
  AutocompleteItem,
  AutocompleteGroup,
  AutocompleteLabel,
  AutocompleteCollection,
} from '@appica/ui-react/autocomplete'

interface ProduceGroup {
  value: string
  items: string[]
}

const groups: ProduceGroup[] = [
  { value: 'Fruits', items: ['Apple', 'Banana', 'Cherry', 'Grapefruit', 'Mango', 'Orange', 'Strawberry'] },
  { value: 'Vegetables', items: ['Broccoli', 'Carrot', 'Cucumber', 'Lettuce', 'Potato', 'Spinach', 'Tomato'] },
  { value: 'Herbs', items: ['Basil', 'Mint', 'Oregano', 'Parsley', 'Rosemary', 'Thyme'] },
]

export default function AutocompleteGrouped() {
  return (
    <div className="w-full max-w-70">
      <Autocomplete items={groups}>
        <AutocompleteInput placeholder="Search produce" aria-label="Search produce" />
        <AutocompleteContent>
          <AutocompleteEmpty>No produce found.</AutocompleteEmpty>
          <AutocompleteList>
            {(group: ProduceGroup) => (
              <AutocompleteGroup key={group.value} items={group.items}>
                <AutocompleteLabel>{group.value}</AutocompleteLabel>
                <AutocompleteCollection>
                  {(item: string) => (
                    <AutocompleteItem key={item} value={item}>
                      {item}
                    </AutocompleteItem>
                  )}
                </AutocompleteCollection>
              </AutocompleteGroup>
            )}
          </AutocompleteList>
        </AutocompleteContent>
      </Autocomplete>
    </div>
  )
}
```

### Grid layout [#grid-layout]

Set `grid` on the root to lay options out in a grid (arrow keys move in two dimensions). `AutocompleteList`'s `cols` controls how many items per row.

```tsx
'use client'

import {
  Autocomplete,
  AutocompleteInput,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteList,
  AutocompleteItem,
} from '@appica/ui-react/autocomplete'

const tags = ['React', 'Vue', 'Svelte', 'Angular', 'Solid', 'Qwik', 'Preact', 'Lit']

export default function AutocompleteGrid() {
  return (
    <div className="w-full max-w-70">
      <Autocomplete items={tags} grid icon>
        <AutocompleteInput placeholder="Search a library" aria-label="Search a library" />
        <AutocompleteContent>
          <AutocompleteEmpty>No libraries found.</AutocompleteEmpty>
          <AutocompleteList cols={2}>
            {(item: string) => (
              <AutocompleteItem key={item} value={item} className="flex-1">
                {item}
              </AutocompleteItem>
            )}
          </AutocompleteList>
        </AutocompleteContent>
      </Autocomplete>
    </div>
  )
}
```

### Controlled [#controlled]

Drive the input value yourself with `value` + `onValueChange` - useful for syncing with form state or reacting to every keystroke.

```tsx
'use client'

import * as React from 'react'
import {
  Autocomplete,
  AutocompleteInput,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteList,
  AutocompleteItem,
} from '@appica/ui-react/autocomplete'

const frameworks = ['Next.js', 'Remix', 'Astro', 'Nuxt.js', 'SvelteKit', 'SolidStart', 'Gatsby', 'Vite']

export default function AutocompleteControlled() {
  const [value, setValue] = React.useState('')

  return (
    <div className="flex w-full max-w-70 flex-col gap-3">
      <Autocomplete items={frameworks} value={value} onValueChange={(v: string) => setValue(v)} clearable>
        <AutocompleteInput placeholder="Search a framework" aria-label="Search a framework" />
        <AutocompleteContent>
          <AutocompleteEmpty>No frameworks found.</AutocompleteEmpty>
          <AutocompleteList>
            {(item: string) => (
              <AutocompleteItem key={item} value={item}>
                {item}
              </AutocompleteItem>
            )}
          </AutocompleteList>
        </AutocompleteContent>
      </Autocomplete>
      <p className="text-foreground-muted text-sm">
        Current value: <span className="text-foreground font-medium">{value || '-'}</span>
      </p>
    </div>
  )
}
```

## RTL [#rtl]

Every Appica UI component supports right-to-left layouts out of the box. Set the `dir` attribute on a container (commonly your `<html>` element) so CSS logical properties resolve correctly, and wrap your tree in `DirectionProvider` so direction-aware behavior (roving focus, popup placement, and the like) follows the same direction.

```tsx
import { DirectionProvider } from '@appica/ui-react/providers/direction-provider'

export default function RootLayout({ children }) {
  return (
    <html lang="ar" dir="rtl">
      <body>
        <DirectionProvider dir="rtl">{children}</DirectionProvider>
      </body>
    </html>
  )
}
```

For setup details and caveats, see the [RTL guide](/ui/docs/react/rtl).


## API reference [#api-reference]

`Autocomplete` wraps [Base UI's Autocomplete](https://base-ui.com/react/components/autocomplete). Each part forwards every remaining prop to the matching Base UI primitive, so anything it accepts works here - the tables below list the Appica additions and the most common props. See the Base UI docs for the complete API.

### Autocomplete [#autocomplete]

The root. Holds the data and the shared styling/behavior options; renders no DOM of its own.

| Prop                   | Type          | Default     | Description                                   |
| ---------------------- | ---------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------ |
| `items`                | `readonly T\[] \| {'{ value, items }[]'}` | -           | The data to filter. A flat array, or `{ value, items }` objects for grouped options. |
| `size`                 | `'sm' \| 'md' \| 'lg'`                    | `'md'`      | Input height, popup radius, and item sizing.                                         |
| `variant`              | `'outline' \| 'soft'`                     | `'outline'` | Input appearance - bordered or filled.                                               |
| `clearable`            | `boolean`                                            | `false`     | Render a clear button inside the input when a value is present.                      |
| `icon`                 | `boolean`                                            | `false`     | Render a chevron button that toggles the popup.                                      |
| `grid`                 | `boolean`                                            | `false`     | Lay options out as a navigable grid instead of a list.                               |
| `value`                | `string`                                             | -           | Controlled input value. Pair with `onValueChange`.                                   |
| `defaultValue`         | `string`                                             | -           | Uncontrolled initial input value.                                                    |
| `onValueChange`        | `(value, details) => void`                | -           | Fires as the value changes (typing, selection, clear).                               |
| `itemToStringValue`    | `(item: T) => string`                     | -           | Required for object items: how the filter and input read each one.                   |
| `mode`                 | `'list' \| 'inline' \| 'both' \| 'none'`  | `'list'`    | Inline modes autofill the input with the highlighted item while navigating.          |
| `filter`               | `function`                                           | -           | Match items against the query. Return `true` to keep an item.                        |
| `children`             | `ReactNode`                                          | -           | The content.                                                                         |
| `inline`               | `boolean`                                            | `false`     | Render the list inline instead of in a popup. Pair with an unconditional `open`.     |
| `disabled`             | `boolean`                                            | `false`     | Disable user interaction.                                                            |
| `onOpenChange`         | `function`                                           | -           | Fires when the popup opens or closes.                                                |
| `name`                 | `string`                                             | -           | Hidden input name for form submission.                                               |
| `modal`                | `boolean`                                            | `false`     | Trap interaction inside the popup while it is open.                                  |
| `actionsRef`           | `Ref`                                                | -           | Ref exposing imperative `unmount()` / `close()`.                                     |
| `open`                 | `boolean`                                            | -           | Controlled open state. Pair with `onOpenChange`.                                     |
| `defaultOpen`          | `boolean`                                            | `false`     | Uncontrolled initial open state.                                                     |
| `onOpenChangeComplete` | `function`                                           | -           | Fires once the open/close animation finishes.                                        |
| `autoHighlight`        | `boolean`                                            | `false`     | Highlight the first match automatically as the user types.                           |
| `keepHighlight`        | `boolean`                                            | `false`     | Keep the highlight when the pointer leaves the list.                                 |
| `highlightItemOnHover` | `boolean`                                            | `true`      | Highlight items as the pointer moves over them.                                      |
| `openOnInputClick`     | `boolean`                                            | `false`     | Open the popup when the input is clicked.                                            |
| `required`             | `boolean`                                            | `false`     | Require a value before the form can submit.                                          |
| `readOnly`             | `boolean`                                            | `false`     | Prevent choosing a different option.                                                 |
| `loopFocus`            | `boolean`                                            | `true`      | Wrap arrow-key focus from the end of the list back to the input.                     |
| `onItemHighlighted`    | `function`                                           | -           | Fires when an item is highlighted or unhighlighted.                                  |
| `inputRef`             | `Ref`                                                | -           | Ref to the hidden input element.                                                     |
| `filteredItems`        | `array`                                              | -           | Pre-filtered items to render, bypassing the built-in filter.                         |
| `virtualized`          | `boolean`                                            | `false`     | Tell the list its items are virtualized externally.                                  |
| `limit`                | `number`                                             | `-1`        | Maximum items to render. `-1` for no limit.                                          |
| `locale`               | `string`                                             | -           | Locale used for string comparison. Defaults to the runtime locale.                   |
| `submitOnItemClick`    | `boolean`                                            | `false`     | Submit the owning form when an item is clicked.                                      |

### AutocompleteInput [#autocompleteinput]

The text field. Renders Base UI's `Input` inside an `InputGroup`, styled like [`Input`](/ui/components/react/input).

| Prop          | Type                                                          | Default | Description                                                           |
| ------------- | ------------------------------------------------------------- | ------- | --------------------------------------------------------------------- |
| `startSlot`   | `ReactNode`                                                   | -       | Adornment rendered before the field, inside the input frame.          |
| `endSlot`     | `ReactNode`                                                   | -       | Adornment rendered after the field, inside the input frame.           |
| `placeholder` | `string`                                                      | `' '`   | Placeholder text.                                                     |
| `disabled`    | `boolean`                                                     | `false` | Disables the field and the clear/chevron buttons.                     |
| `render`      | `ReactElement \| ((props, state) => ReactElement)` | -       | Replace the underlying element, or compose it with another component. |
| `className`   | `string`                                                      | -       | Extra classes on the input group, merged via `tailwind-merge`.        |

Also forwards every native `<input>` prop (`onChange`, `name`, `aria-*`, `ref`, …).

### AutocompleteContent [#autocompletecontent]

The portalled, auto-positioned popup wrapping the list. Accepts the shared floating props.

| Prop                    | Type                                           | Default                | Description                                                           |
| ----------------------- | ------------------------------------------------------------------------------------- | ---------------------- | --------------------------------------------------------------------- |
| `side`                  | `'top' \| 'right' \| 'bottom' \| 'left' \| 'inline-end' \| 'inline-start'` | `'bottom'`             | Preferred side of the input to open on.                               |
| `align`                 | `'start' \| 'center' \| 'end'`                                             | -                      | Alignment along that side.                                            |
| `sideOffset`            | `number`                                                                              | `6`                    | Gap between the input and the popup.                                  |
| `alignOffset`           | `number`                                                                              | -                      | Shift along the alignment axis.                                       |
| `container`             | `HTMLElement \| ref \| null`                                               | -                      | Portal target - render the popup into a different node.               |
| `keepMounted`           | `boolean`                                                                             | `false`                | Keep the popup mounted in the DOM while closed.                       |
| `positionerProps`       | `object`                                                                              | -                      | Escape hatch for the positioner element (`style`, `render`, …).       |
| `portalProps`           | `object`                                                                              | -                      | Escape hatch for the portal element (`style`, `render`, …).           |
| `render`                | `ReactElement \| ((props, state) => ReactElement)`                         | -                      | Replace the underlying element, or compose it with another component. |
| `initialFocus`          | `boolean \| ref \| function`                                               | -                      | Where focus goes when the popup opens.                                |
| `finalFocus`            | `boolean \| ref \| function`                                               | -                      | Where focus goes when the popup closes.                               |
| `anchor`                | `Element \| ref \| VirtualElement`                                         | -                      | Element to position against, instead of the trigger.                  |
| `positionMethod`        | `'absolute' \| 'fixed'`                                                    | `'absolute'`           | CSS `position` used for the popup.                                    |
| `collisionBoundary`     | `Boundary`                                                                            | `'clipping-ancestors'` | Element or rectangle the popup is confined to.                        |
| `collisionPadding`      | `number`                                                                              | `5`                    | Extra space to keep from the boundary edge.                           |
| `collisionAvoidance`    | `CollisionAvoidance`                                                                  | -                      | How the popup reacts when it would overflow the boundary.             |
| `sticky`                | `boolean`                                                                             | `false`                | Keep the popup in view after the anchor scrolls away.                 |
| `arrowPadding`          | `number`                                                                              | `5`                    | Minimum gap between the arrow and the popup's corners.                |
| `disableAnchorTracking` | `boolean`                                                                             | `false`                | Stop the popup following layout shifts of its anchor.                 |
| `className`             | `string`                                                                              | -                      | Extra classes on the popup.                                           |

### AutocompleteList [#autocompletelist]

The scrollable list container.

| Prop        | Type                   | Default | Description                                                               |
| ----------- | ------------------------------------------------------------- | ------- | ------------------------------------------------------------------------- |
| `cols`      | `number`                                                      | -       | Items per row in grid mode (defaults to 2 when `grid` is set).            |
| `className` | `string`                                                      | -       | Extra classes, merged via `tailwind-merge`.                               |
| `render`    | `ReactElement \| ((props, state) => ReactElement)` | -       | Replace the underlying element, or compose it with another component.     |
| `children`  | `ReactNode \| (item, index) => ReactNode`          | -       | A render function over the filtered items, or static `AutocompleteItem`s. |

### AutocompleteItem [#autocompleteitem]

One option in the list.

| Prop           | Type                                                          | Default | Description                                                               |
| -------------- | ------------------------------------------------------------- | ------- | ------------------------------------------------------------------------- |
| `value`        | `T`                                                           | -       | The item this option represents; reported on selection.                   |
| `children`     | `ReactNode`                                                   | -       | The content.                                                              |
| `index`        | `number`                                                      | -       | The item's index in the list. Set it to skip automatic index calculation. |
| `disabled`     | `boolean`                                                     | `false` | Disable user interaction.                                                 |
| `nativeButton` | `boolean`                                                     | `false` | Whether `render` produces a native `<button>`. Set `true` when it does.   |
| `render`       | `ReactElement \| ((props, state) => ReactElement)` | -       | Replace the underlying element, or compose it with another component.     |
| `className`    | `string`                                                      | -       | Extra classes (e.g. `flex-1` to fill a grid cell).                        |

### AutocompleteEmpty [#autocompleteempty]

Shown only when the filter matches nothing - otherwise it renders nothing.

| Prop        | Type                                                          | Default | Description                                                           |
| ----------- | ------------------------------------------------------------- | ------- | --------------------------------------------------------------------- |
| `render`    | `ReactElement \| ((props, state) => ReactElement)` | -       | Replace the underlying element, or compose it with another component. |
| `children`  | `ReactNode`                                                   | -       | The empty-state message.                                              |
| `className` | `string`                                                      | -       | Extra classes, merged via `tailwind-merge`.                           |

### AutocompleteStatus [#autocompletestatus]

A persistent row that stays mounted (e.g. a loading or count message), unlike `AutocompleteEmpty`.

| Prop        | Type                                                          | Default | Description                                                           |
| ----------- | ------------------------------------------------------------- | ------- | --------------------------------------------------------------------- |
| `render`    | `ReactElement \| ((props, state) => ReactElement)` | -       | Replace the underlying element, or compose it with another component. |
| `children`  | `ReactNode`                                                   | -       | The status message.                                                   |
| `className` | `string`                                                      | -       | Extra classes, merged via `tailwind-merge`.                           |

### AutocompleteGroup [#autocompletegroup]

Wraps one labeled section of a grouped list.

| Prop        | Type                                                          | Default | Description                                                            |
| ----------- | ------------------------------------------------------------- | ------- | ---------------------------------------------------------------------- |
| `items`     | `readonly T[]`                                                | -       | The group's items, so the inner `AutocompleteCollection` can map them. |
| `render`    | `ReactElement \| ((props, state) => ReactElement)` | -       | Replace the underlying element, or compose it with another component.  |
| `className` | `string`                                                      | -       | Extra classes, merged via `tailwind-merge`.                            |

### AutocompleteLabel [#autocompletelabel]

The visible label for an `AutocompleteGroup`.

| Prop        | Type                                                          | Default | Description                                                           |
| ----------- | ------------------------------------------------------------- | ------- | --------------------------------------------------------------------- |
| `render`    | `ReactElement \| ((props, state) => ReactElement)` | -       | Replace the underlying element, or compose it with another component. |
| `children`  | `ReactNode`                                                   | -       | The label text.                                                       |
| `className` | `string`                                                      | -       | Extra classes, merged via `tailwind-merge`.                           |

### AutocompleteCollection [#autocompletecollection]

Renders the items inside an `AutocompleteGroup`.

| Prop       | Type | Default | Description                                                         |
| ---------- | ------------------------------------------- | ------- | ------------------------------------------------------------------- |
| `children` | `(item, index) => ReactNode`     | -       | Render function for each item - `(item) => <AutocompleteItem … />`. |

### AutocompleteSeparator [#autocompleteseparator]

A thin divider between sections.

| Prop          | Type                                                          | Default        | Description                                                           |
| ------------- | ------------------------------------------------------------- | -------------- | --------------------------------------------------------------------- |
| `render`      | `ReactElement \| ((props, state) => ReactElement)` | -              | Replace the underlying element, or compose it with another component. |
| `orientation` | `'horizontal' \| 'vertical'`                       | `'horizontal'` | Layout axis.                                                          |
| `className`   | `string`                                                      | -              | Extra classes, merged via `tailwind-merge`.                           |

### AutocompleteTrigger [#autocompletetrigger]

A standalone button that opens the popup (e.g. a tag picker that isn't a text field).

| Prop           | Type                   | Default | Description                                                                  |
| -------------- | ------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------- |
| `disabled`     | `boolean`                                                     | `false` | Disable user interaction.                                                    |
| `nativeButton` | `boolean`                                                     | `true`  | Whether `render` produces a native `<button>`. Set `false` when it does not. |
| `render`       | `ReactElement \| ((props, state) => ReactElement)` | -       | Compose the trigger with another element.                                    |
| `className`    | `string`                                                      | -       | Extra classes, merged via `tailwind-merge`.                                  |

Also forwards every native `<button>` prop (`onClick`, `aria-*`, `ref`, …).

### AutocompleteValue [#autocompletevalue]

Renders the current value for read-only display.

| Prop       | Type    | Default | Description                                        |
| ---------- | ---------------------------------------------- | ------- | -------------------------------------------------- |
| `children` | `ReactNode \| (value) => ReactNode` | -       | Static content, or a render function of the value. |

## Accessibility [#accessibility]

* The input has `role="combobox"`; the popup is a `listbox` (or `grid` when `grid` is set) and items are `option`/`gridcell`. Selection and active state are wired through `aria-activedescendant`.
* **↑/↓** move the highlight, **Enter** selects, **Escape** closes the popup, and typing filters the list.
* The clear and chevron buttons have `aria-label`s (`Clear selection`, `Toggle popup`) and become `disabled` when the input is disabled.
* Always give `AutocompleteInput` a visible label or an `aria-label`.
* Popup enter/exit transitions are wrapped so they're skipped when the user prefers reduced motion.
