Autocomplete

A text input paired with a filtered list of suggestions, from @clerk/headless. It is a headless primitive: it supplies input text, selected value, and open state, portalling, floating-ui positioning, virtual-focus keyboard navigation, and ARIA combobox wiring, but ships no styles — you bring your own CSS by targeting the data-* attributes each part emits. It does no filtering of its own: you read inputValue and render the surviving options.

Example

The demo below is intentionally unstyled — it renders the raw primitive so you can see its behavior and ARIA wiring. Type to filter the consumer-supplied list; arrow keys move the active option and Enter selects it.

Usage

import { Autocomplete } from '@clerk/headless/autocomplete';

const [inputValue, setInputValue] = useState('');
const filtered = items.filter(item => item.toLowerCase().includes(inputValue.toLowerCase()));

<Autocomplete.Root
  inputValue={inputValue}
  onInputValueChange={setInputValue}
>
  <Autocomplete.Input placeholder='Search…' />
  <Autocomplete.Portal>
    <Autocomplete.Positioner>
      <Autocomplete.Popup>
        <Autocomplete.List>
          {filtered.map(item => (
            <Autocomplete.Option
              key={item}
              value={item}
              label={item}
            >
              {item}
            </Autocomplete.Option>
          ))}
        </Autocomplete.List>
      </Autocomplete.Popup>
    </Autocomplete.Positioner>
  </Autocomplete.Portal>
</Autocomplete.Root>;

Parts

PartDefault ElementDescription
Autocomplete.Rootnone (context)Owns input text, selected value, open state, and positioning
Autocomplete.Input<input>The combobox text input that drives filtering and navigation
Autocomplete.Portalnone (portal)Portals its children; renders nothing until mounted
Autocomplete.Positioner<div>Floating-positioned container
Autocomplete.Popup<div>Visual wrapper for the option list
Autocomplete.List<div>Listbox container (use inline, inside another floating surface)
Autocomplete.Option<div>A selectable option (role="option")
Autocomplete.Arrow<svg>Optional arrow pointing at the input

All rendered parts accept a render prop for polymorphic rendering and standard HTML attributes for their default element. Autocomplete.Arrow accepts floating-ui FloatingArrow props. Mounting Autocomplete.List switches the primitive into inline mode (Escape / outside press bubble to the parent floating surface instead of dismissing).

Props

Autocomplete.Root

PropTypeDefaultDescription
inputValuestringControlled input text
defaultInputValuestring''Initial input text (uncontrolled)
onInputValueChange(value: string) => voidCalled when the input text changes
valuestringControlled selected value
defaultValuestringInitial selected value (uncontrolled)
onValueChange(value: string) => voidCalled when an option is selected
openbooleanControlled open state
defaultOpenbooleanfalseInitial open state (uncontrolled)
onOpenChange(open: boolean) => voidCalled when the open state changes
placementPlacement'bottom-start'Placement relative to the input
sideOffsetnumber4Gap in px between the input and the popup

Autocomplete.Option

PropTypeDefaultDescription
valuestring— (required)The option's value
labelstringfalls back to valueLabel written to the input when selected
disabledbooleanPrevent selection

Autocomplete.Input, Autocomplete.Positioner, Autocomplete.Popup, and Autocomplete.List take no additional props beyond standard HTML attributes for their default element. Autocomplete.Portal accepts root.

Styling

Each part emits data-* attributes you can target with any CSS solution:

AttributeApplies ToDescription
data-openInputPresent when the popup is open
data-closedInputPresent when the popup is closed
data-selectedOptionPresent on the option matching the selected value
data-activeOptionPresent on the keyboard-highlighted option
data-disabledOptionPresent on a disabled option
data-sidePositioner, ArrowResolved side: top / bottom / left / right

The positioner exposes anchor/viewport geometry as CSS variables (and sets an inline width matching the input and a max-height of the available viewport height):

VariableDescription
--cl-anchor-widthInput width
--cl-anchor-heightInput height
--cl-available-widthAvailable width between the anchor and viewport edge
--cl-available-heightAvailable height between the anchor and viewport edge
--cl-transform-origintransform-origin pointing back toward the anchor