Noctis

Autocomplete

A free-text input with a suggestion list: as the user types, Autocomplete.Content floats a filtered list of suggestions beneath the field. Unlike Combobox, the committed value is the typed text — the suggestions complete and accelerate free entry rather than constraining it to a fixed option set.

Basic

Autocomplete.Root owns the state and the items; Autocomplete.Input is the field, and Autocomplete.Content floats the popup as the user types — an Autocomplete.List mapping each item to an Autocomplete.Item, with an Autocomplete.Empty line for when nothing matches. Wrap the input in an Autocomplete.InputGroup to seat a leading Autocomplete.Icon and a trailing Autocomplete.Clear (shown only while the field holds a value, refocusing the input on click) inside the field. The field follows the rest of the field family — a filled surface, a calm ring-less focus that shifts only the border, and a subtle rest shadow.

Sizes

The root's sizemd (the default) or lg — sets the field's control height and the popup's row density together, so a large field opens a large-density popup. Set it once on Autocomplete.Root.

With icons

Give each Autocomplete.Item a leading icon to label the suggestion's kind. The glyph sits quieter than the label and the row lights up with a neutral highlight on hover or keyboard focus — the accent stays a signal, never a hover fill.

Match highlighting

Bold the part of each suggestion that matches the typed query with Autocomplete.Highlight — pass it the row's text and the current query. The match is weight-and-foreground only (no highlight background, never the accent) so it reads clearly while the list stays quiet — the signature autocomplete moment.

Async loading

Autocomplete from a server: set loading on Autocomplete.Root while a request is in flight — render an Autocomplete.Loading in the InputGroup for the trailing spinner (which also sets aria-busy on the field) — and render an Autocomplete.Status inside the Content so a screen reader hears the "Searching…" state and the results count politely. Disable the built-in filter (filter={null}) when you filter on the server, and debounce the input (keep predictions under ~1s). When nothing matches, the Empty interpolates the query.

Create on the fly

Because the committed value is free text, the no-match case can become an action: render an Autocomplete.Create row with value set to the typed query when there is no exact match, so committing it accepts the typed value. The row is slightly emphasized with a leading "+" — the differentiator versus Combobox's constrained selection.

Auto-highlight

Set autoHighlight on Autocomplete.Root to keep the first match highlighted as the user types, so Enter commits it without arrowing down — a keyboard-first win for fast entry. (Pass autoHighlight="always" to keep the first row highlighted even before typing.)

Inline completion

Set mode="both" to filter the list and complete the first match inline — the field temporarily shows the highlighted suggestion as a selected range you can accept or type past. Pair it with autoHighlight so the top match is active and Enter commits it without arrowing. (mode="inline" completes without filtering; mode="list", the default, only filters; mode="none" does neither.)

Recent and suggestions

Section the popup with Autocomplete.Group + Autocomplete.GroupLabel, mapping each group's filtered items through Autocomplete.Collection, and divide sections with Autocomplete.Separator. Set openOnFocus on the root so the sections surface the moment the field is focused — the command-palette idiom — with recents in reverse-chronological order.

Limiting results

For a long catalog, cap the visible rows with limit on Autocomplete.Root and render an Autocomplete.Status that says how many of the total matched, so a keyboard user knows the list is truncated.

Validation

As a member of the field family, Autocomplete takes the shared invalid contract: compose it inside a Field.Root for the full label / description / error wiring, and the field reports invalid through Field automatically. Set invalid on Autocomplete.Input as an additive override. Invalid shifts the border to the danger role — the same recipe as Input and Combobox, no bespoke red and no extra ring.

Keyboard

Filtering and navigation are Base UI's, fully keyboard-operable and RTL-aware. Focus stays on the input; aria-autocomplete resolves to list for mode="list" and both for mode="both", aria-activedescendant tracks the highlighted row, and aria-expanded mirrors the popup's open state.

KeyAction
TypeFilter the suggestions and open the popup; in both/inline mode, inline-complete the first match into a selected range.
/ Open if closed; move the highlight through the suggestions.
Alt + Open the popup without moving the highlight.
Home / EndMove the text caret to the start / end of the field.
EnterCommit the highlighted (or auto-highlighted) suggestion; accept the typed value on a Create row.
EscClose the popup, keeping the typed text.

Accessibility

  • Async announcements. Autocomplete.Status is a polite live region that must stay mounted — Base UI announces its content changes (searching, results count) without moving focus. The trailing Loading spinner also carries a localized hidden "Loading" label and sets aria-busy on the field.
  • Affordance labels. Clear is an icon-only button; it carries a localized default aria-label you can override. The leading Icon is decorative (aria-hidden).
  • Inverted contrast. The match <mark> is weight + foreground on a transparent ground, so it never relies on colour alone.
  • Known gap. Base UI's internal dismiss control has a hardcoded English aria-label that no consumer prop reaches, so it is not yet translatable from this layer — pending an upstream Base UI change. Everything else localizes through the active locale.
  • Reduced motion. The popup scale and the loading spinner both respect prefers-reduced-motion; the spinner falls back to a static glyph, and the Status text still conveys progress.

Anatomy

Compose an autocomplete from its parts. Autocomplete.Root owns the state, the items, and the control size, and shares the size and the loading flag with the field and rows through context.

  • Autocomplete.Root — owns the suggestion items, the input value (value / onValueChange, or defaultValue), the open state, the mode (list / both / inline / none), autoHighlight, openOnFocus, loading, limit, and the control size. Renders no element.
  • Autocomplete.Input — the text field; takes an optional size override and an invalid flag.
  • Autocomplete.InputGroup — the field shell that lays the input beside its leading Icon and trailing Clear / Loading affordances.
  • Autocomplete.Icon — a leading decorative field glyph (search magnifier by default).
  • Autocomplete.Clear — a button that clears the value, shown only while the field holds one.
  • Autocomplete.Loading — the trailing async spinner, shown while the root is loading.
  • Autocomplete.Content — the portalled, elevated popup (a Surface); takes side / align / sideOffset / collisionPadding positioning props.
  • Autocomplete.List — the scrollable listbox; pass a render function to map each filtered item to an Item.
  • Autocomplete.Item — one suggestion row, with an optional leading icon.
  • Autocomplete.Create — the conditional free-text "Use «query»" row; give it the typed query as its value.
  • Autocomplete.Highlight — bolds the matched substring of a suggestion (text + query).
  • Autocomplete.Empty — the polite no-matches message shown inside the popup.
  • Autocomplete.Status — a polite status line for an asynchronously loaded list.
  • Autocomplete.Group + Autocomplete.GroupLabel + Autocomplete.Collection + Autocomplete.Separator — a labelled section, its filtered rows, and the divider between sections.

Every rendered part carries a data-slot under the noctis-autocomplete-* prefix (-input, -content, -list, -item, -empty, -status, -group-label, and the styling-only -input-group, -icon, -clear, -loading, -mark, -positioner, -group, -separator) for host-side styling. The field and popup mirror the root size as data-size; a suggestion row marks the active item with data-highlighted, dims on data-disabled, and the field carries data-invalid while invalid.

On surfaces

The same control re-tuned across the elevation scopes — the root canvas, an elevated panel, a menu, and a sunken well. It stays legible on every layer.

root
elevated
menu
sunken

Design tokens

Generated from the component's declaration — the same graph that mints the CSS, so a variable name or its resolution default can't drift. The minted tokens are the public override seam: set one on any ancestor and every autocomplete in that region retunes — e.g. .dense { --noctis-autocomplete-item-height: 1.75rem; } tightens every suggestion row beneath it. Knobs that aren't minted are reached through the part's data-slot. See Customization for the full override ladder and Tokens for the whole graph.

Token

API reference

Generated from the component's types — every prop, type, default, and description comes straight from the source. Each part gets its own table; the Root carries the items, value, and open-state props that the parts read through context. Expand a row for the full type and description.

Autocomplete.Root

Prop

Autocomplete.Input

Prop

Autocomplete.InputGroup

Prop

Autocomplete.Icon

Prop

Autocomplete.Clear

Prop

Autocomplete.Loading

Prop

Autocomplete.Content

Prop

Autocomplete.List

Prop

Autocomplete.Item

Prop

Autocomplete.Create

Prop

Autocomplete.Highlight

Prop

Autocomplete.Empty

Prop

Autocomplete.Status

Prop

Autocomplete.Group

Prop

Autocomplete.GroupLabel

Prop

Autocomplete.Collection

No props of its own — forwards to the underlying Base UI part.

Autocomplete.Separator

Prop

AttributeDescription
data-slotMarks each rendered part.
data-sizeThe control size mirrored from the root's `size` (`md`/`lg`); the field height and popup density key off it.
data-popup-openPresent on the input while its suggestions popup is open.
data-highlightedPresent on the suggestion row the pointer or keyboard is currently over.
data-disabledPresent on a disabled suggestion row or input.
data-invalidPresent on the input/field when the field is invalid (set explicitly or by a `Field`).
data-createPresent on the `Create` row, for its slightly emphasized free-text-entry styling.
data-sideThe side of the anchor the popup actually rendered on (`bottom`, `top`, …).
data-emptyPresent on the popup while its suggestions list is empty.
data-starting-stylePresent on the popup for the first frame after mount — the transition's start state.
data-ending-stylePresent on the popup while it transitions out before unmounting.