sc1m/design
ComponentsAutocomplete

Autocomplete

Autocomplete component built on Base UI, styled with sc1m tokens.

StableBase UI

Live preview

Installation

pnpm dlx shadcn@latest add @sc1m/autocomplete

This also merges the token layer and installs src/lib/cn.ts plus @base-ui/react. For the manual route — prerequisites, components.json, and app-level setup — see Installation.

Usage

import {
  Autocomplete,
  AutocompleteInput,
  AutocompleteContent,
  AutocompleteList,
  AutocompleteItem,
  AutocompleteEmpty,
} from "@/components/ui/autocomplete";

Composition

Every part is a separate export. Autocomplete owns state; the rest are presentational and must appear in this order.

Autocomplete├── AutocompleteInput└── AutocompleteContent    ├── AutocompleteEmpty    └── AutocompleteList        └── AutocompleteItem

Example

The preview above, with its source. This is the demo module verbatim, so the code and the thing it renders cannot drift apart.

<Autocomplete items={fruits}>
  <AutocompleteInput placeholder="Search fruits…" />
  <AutocompleteContent>
    <AutocompleteEmpty>No fruits found.</AutocompleteEmpty>
    <AutocompleteList>
      {(fruit: string) => (
        <AutocompleteItem key={fruit} value={fruit}>
          {fruit}
        </AutocompleteItem>
      )}
    </AutocompleteList>
  </AutocompleteContent>
</Autocomplete>

API reference

Each part forwards every prop of its Base UI counterpart; the tables list the ones declared on the part itself. See Base UI's reference for the inherited element props.

Autocomplete

PropTypeDefaultDescription
formstringIdentifies the form that owns the internal input.
mode'list' | 'both' | 'inline' | 'none''list'Controls how the autocomplete behaves with respect to list filtering and inline autocompletion.
inlinebooleanfalseWhether the list is rendered inline without using the component's own popup.
autoHighlightboolean | 'always'falseWhether the first matching item is highlighted automatically.
keepHighlightbooleanfalseWhether the highlighted item should be preserved when the pointer leaves the list.
highlightItemOnHoverbooleantrueWhether moving the pointer over items should highlight them.
defaultValueAriaCombobox.Props<React.ComponentProps<'input'>['defaultValue'], 'none'>['defaultInputValue']The uncontrolled input value of the autocomplete when it's initially rendered.
valueAriaCombobox.Props<React.ComponentProps<'input'>['value'], 'none'>['inputValue']The input value of the autocomplete.
onValueChange((value: string, eventDetails: AutocompleteRootChangeEventDetails) => void)Event handler called when the input value of the autocomplete changes.
submitOnItemClickAriaCombobox.Props<ItemValue, 'none'>['submitOnItemClick']falseWhether clicking an item should submit the autocomplete's owning form.
itemToStringValue((itemValue: ItemValue) => string)When the item values are objects (<Autocomplete.Item value={object}>), this function converts the object value to a string representation for both display in the input and form submission.
actionsRefReact.RefObject<AutocompleteRootActions | null>A ref to imperative actions.
onOpenChange((open: boolean, eventDetails: AutocompleteRootChangeEventDetails) => void)Event handler called when the popup is opened or closed.
onItemHighlighted((highlightedValue: ItemValue | undefined, eventDetails: AutocompleteRootHighlightEventDetails) => void)Callback fired when an item is highlighted or unhighlighted.
openOnInputClickbooleanfalseWhether the popup opens when clicking the input.

AutocompleteItem

PropTypeDefaultDescription
onClickBaseUIComponentProps<'div', AutocompleteItemState>['onClick']An optional click handler for the item when selected.
indexnumberThe index of the item in the list.
valueanynullA unique value that identifies this item.
disabledbooleanfalseWhether the component should ignore user interaction.

Accessibility

Behaviour, focus management, and ARIA wiring come from Base UI's Autocomplete — see its reference for the full keyboard map.

  • Keyboard focus draws a 2px ring in --ring, never removed — only shown on :focus-visible, so a pointer press does not paint one.
  • Disabled parts mute their contents rather than the element, keeping the focus ring at full strength where the part stays focusable.

Design tokens

The component reads semantic tokens only — no raw colour, radius, or duration appears in its source. Override the token, not the component.

TokenApplied to
--brand-radius-mdAutocompleteInput, AutocompleteContent
--brand-radius-smAutocompleteItem
--fgAutocompleteInput, AutocompleteContent, AutocompleteItem
--fg-subtleAutocompleteInput, AutocompleteEmpty
--lineAutocompleteInput, AutocompleteContent
--ringAutocompleteInput
--shadow-overlayAutocompleteContent
--surfaceAutocompleteItem
--surface-raisedAutocompleteInput, AutocompleteContent

Source

src/components/ui/autocomplete/autocomplete.tsx — no next/* imports, so it drops into any React 19 + Tailwind v4 app.