moduix

Autocomplete

An input that suggests matching options while preserving free-form text.

API Reference

Original primitive API

Behavior, accessibility details, and low-level props are documented by Base UI.

Base UI API

Choosing the right component

Use Autocomplete when users need to type freely and you want to suggest matching options while they type.

  • Choose Autocomplete for free-form values with suggestions.
  • Choose Combobox when users should select from predefined options, with typing used to filter.
  • Choose Select for strict pickers with no text input in the trigger.

Basic

import {  Autocomplete,  AutocompleteField,  AutocompleteFieldLabel,  AutocompleteInputGroup,  AutocompleteInput,  AutocompleteControlActions,  AutocompleteClear,  AutocompleteTrigger,  AutocompleteContent,  AutocompleteEmpty,  AutocompleteList,  AutocompleteItem,  AutocompleteItemText,} from "moduix";import { useId } from "react";export function AutocompleteDemo() {  const id = useId();  return (    <Autocomplete items={tags} itemToStringValue={(item) => item.value}>      <AutocompleteField>        <AutocompleteFieldLabel htmlFor={id}>Search tags</AutocompleteFieldLabel>        <AutocompleteInputGroup>          <AutocompleteInput id={id} placeholder="e.g. feature" />          <AutocompleteControlActions>            <AutocompleteClear aria-label="Clear value" />            <AutocompleteTrigger aria-label="Open suggestions" />          </AutocompleteControlActions>        </AutocompleteInputGroup>      </AutocompleteField>      <AutocompleteContent>        <AutocompleteEmpty>No tags found.</AutocompleteEmpty>        <AutocompleteList>          {(item) => (            <AutocompleteItem key={item.id} value={item}>              <AutocompleteItemText>{item.value}</AutocompleteItemText>            </AutocompleteItem>          )}        </AutocompleteList>      </AutocompleteContent>    </Autocomplete>  );}
const tags = [  { id: "t1", value: "feature" },  { id: "t2", value: "fix" },  { id: "t3", value: "bug" },  { id: "t4", value: "docs" },];

Full list of component variables available for project-level overrides.

PropertyDefaultDescription
--autocomplete-action-bg-hovervar(--color-muted)Controls trigger and clear hover background.
--autocomplete-action-color-hovervar(--color-foreground)Controls trigger and clear hover color.
--autocomplete-action-radiusvar(--radius-sm)Controls trigger and clear button radius.
--autocomplete-action-size1.5remControls trigger and clear button size.
--autocomplete-actions-gap0.125remControls spacing between trigger and clear buttons.
--autocomplete-actions-offset-right0.5remControls right offset for control actions.
--autocomplete-arrow-height0.625remControls optional popup arrow height.
--autocomplete-arrow-inline-offset13pxControls arrow inline-side offset.
--autocomplete-arrow-size8pxControls arrow side offset size.
--autocomplete-arrow-stroke-colorvar(--autocomplete-popup-border-color)Controls optional popup arrow border color.
--autocomplete-arrow-width1.25remControls optional popup arrow width.
--autocomplete-backdrop-bgvar(--backdrop-bg, var(--color-overlay))Controls optional backdrop color.
--autocomplete-backdrop-blur2pxControls optional backdrop blur.
--autocomplete-backdrop-transitionvar(--transition-default)Controls optional backdrop animation.
--autocomplete-bgvar(--color-background)Controls control background.
--autocomplete-border-colorvar(--color-border)Controls control border color.
--autocomplete-border-widthvar(--border-width-sm)Controls control border width.
--autocomplete-colorvar(--color-foreground)Controls primary text color.
--autocomplete-control-heightvar(--size-lg)Controls input and trigger height.
--autocomplete-empty-colorvar(--color-muted-foreground)Controls empty state text color.
--autocomplete-empty-font-sizevar(--text-sm)Controls empty-state font size.
--autocomplete-empty-line-heightvar(--line-height-text-sm)Controls empty-state line height.
--autocomplete-empty-padding-x1remControls empty-state horizontal padding.
--autocomplete-empty-padding-y0.75remControls empty-state vertical padding.
--autocomplete-field-gap0.375remControls spacing between field label and control.
--autocomplete-field-trigger-bg-openvar(--color-muted)Controls field-trigger background when popup is open.
--autocomplete-focus-ring-colorvar(--color-ring)Controls keyboard focus ring color.
--autocomplete-focus-ring-offsetvar(--autocomplete-border-width)Controls focus ring offset.
--autocomplete-focus-ring-widthvar(--autocomplete-border-width)Controls focus ring width.
--autocomplete-grid-item-min-height2.5remControls grid item minimum height.
--autocomplete-grid-item-padding-xvar(--spacing-2)Controls grid item horizontal padding.
--autocomplete-grid-item-width2.5remControls grid item width.
--autocomplete-group-label-bgvar(--color-popover)Controls group label background.
--autocomplete-group-label-colorvar(--color-muted-foreground)Controls group label color.
--autocomplete-group-label-font-sizevar(--text-xs)Controls group label font size.
--autocomplete-group-label-font-weightvar(--weight-semibold)Controls group label font weight.
--autocomplete-group-label-line-heightvar(--line-height-text-xs)Controls group label line height.
--autocomplete-group-label-padding-bottom0.35remControls group label bottom padding.
--autocomplete-group-label-padding-top0.35remControls group label top padding.
--autocomplete-group-label-padding-x0.625remControls group label horizontal padding.
--autocomplete-group-padding-bottomvar(--spacing-1)Controls group bottom padding.
--autocomplete-highlight-bgvar(--color-foreground)Controls highlighted item background.
--autocomplete-highlight-colorvar(--color-background)Controls highlighted item text color.
--autocomplete-highlight-inset-xvar(--spacing-1)Controls highlighted item horizontal inset.
--autocomplete-highlight-radiusvar(--radius-sm)Controls highlighted item radius.
--autocomplete-icon-colorvar(--color-muted-foreground)Controls default icon color.
--autocomplete-icon-size0.875remControls icon container size.
--autocomplete-icon-svg-size1remControls icon glyph size.
--autocomplete-inline-input-border-widthvar(--border-width-sm)Controls inline input border width.
--autocomplete-inline-input-container-padding-bottomvar(--spacing-2)Controls inline input container bottom padding.
--autocomplete-inline-input-container-padding-topvar(--spacing-2)Controls inline input container top padding.
--autocomplete-inline-input-container-padding-xvar(--spacing-2)Controls inline input container horizontal padding.
--autocomplete-inline-input-divider-colorvar(--autocomplete-border-color)Controls inline input container divider color.
--autocomplete-inline-input-divider-stylesolidControls inline input container divider style.
--autocomplete-inline-input-divider-widthvar(--border-width-sm)Controls inline input container divider width.
--autocomplete-inline-input-padding-x0.75remControls inline input horizontal padding.
--autocomplete-inline-input-radiusvar(--radius-sm)Controls inline input radius.
--autocomplete-inline-list-padding-bottom0.5remControls inline list bottom padding.
--autocomplete-inline-list-padding-top0.375remControls inline list top padding.
--autocomplete-inline-list-scroll-padding-bottom0.5remControls inline list bottom scroll padding.
--autocomplete-inline-list-scroll-padding-top0.375remControls inline list top scroll padding.
--autocomplete-input-group-padding-x0Controls horizontal input-group padding.
--autocomplete-input-padding-x-end3.25remControls input end padding.
--autocomplete-input-padding-x-start0.875remControls input start padding.
--autocomplete-input-placeholder-colorvar(--color-muted-foreground)Controls placeholder color.
--autocomplete-item-colorvar(--color-foreground)Controls item text color.
--autocomplete-item-font-sizevar(--text-sm)Controls item font size.
--autocomplete-item-line-heightvar(--line-height-text-sm)Controls item line height.
--autocomplete-item-min-height2remControls item minimum height.
--autocomplete-item-padding-xvar(--spacing-4)Controls item start padding.
--autocomplete-item-padding-x-end1remControls item end padding.
--autocomplete-item-padding-yvar(--spacing-2)Controls item vertical padding.
--autocomplete-item-text-content-gapvar(--spacing-2)Controls gap between item text content slots.
--autocomplete-item-text-icon-colorcurrentColorControls item text icon color.
--autocomplete-item-text-icon-size1remControls item text icon size.
--autocomplete-label-font-sizevar(--text-sm)Controls field label font size.
--autocomplete-label-font-weightvar(--weight-medium)Controls field label font weight.
--autocomplete-label-line-heightvar(--line-height-text-sm)Controls field label line height.
--autocomplete-list-max-heightvar(--autocomplete-popup-max-height)Controls list max height.
--autocomplete-list-padding-y0.25remControls vertical list padding.
--autocomplete-list-scroll-padding-y0.25remControls list scroll padding.
--autocomplete-popup-bgvar(--color-popover)Controls popup background.
--autocomplete-popup-border-colorvar(--color-border)Controls popup border color.
--autocomplete-popup-border-widthvar(--border-width-sm)Controls popup border width.
--autocomplete-popup-max-height24remControls the popup max height.
--autocomplete-radiusvar(--radius-md)Controls control and popup radius.
--autocomplete-row-gapvar(--spacing-1)Controls grid row item gap.
--autocomplete-row-padding-xvar(--spacing-1)Controls grid row horizontal padding.
--autocomplete-separator-margin-x1remControls separator horizontal margin.
--autocomplete-separator-margin-y0.375remControls separator vertical margin.
--autocomplete-separator-sizevar(--border-width-sm)Controls separator thickness.
--autocomplete-shadowvar(--shadow-lg)Controls popup shadow.
--autocomplete-status-colorvar(--autocomplete-empty-color)Controls status text color.
--autocomplete-status-divider-colorvar(--autocomplete-popup-border-color)Controls status divider color.
--autocomplete-status-divider-widthvar(--border-width-sm)Controls status divider width.
--autocomplete-status-font-sizevar(--text-xs)Controls status font size.
--autocomplete-status-gapvar(--spacing-1)Controls status content gap.
--autocomplete-status-line-heightvar(--line-height-text-xs)Controls status line height.
--autocomplete-status-padding-x0.75remControls status horizontal padding.
--autocomplete-status-padding-y0.5remControls status vertical padding.
--autocomplete-trigger-gap0.75remControls field-trigger content gap.
--autocomplete-trigger-padding-x0.875remControls field-trigger horizontal padding.
--autocomplete-width16remControls the control and popup anchor width.

Interactive variables scoped for docs preview without changing size scale tokens.

PropertyValueDefaultDescription
--autocomplete-bgvar(--color-background)Controls control background.
--autocomplete-border-colorvar(--color-border)Controls control border color.
--autocomplete-colorvar(--color-foreground)Controls primary text color.
--autocomplete-empty-colorvar(--color-muted-foreground)Controls empty text color.
--autocomplete-focus-ring-colorvar(--color-ring)Controls focus ring color.
--autocomplete-group-label-font-weightvar(--weight-semibold)Controls label weight.
--autocomplete-highlight-bgvar(--color-foreground)Controls highlighted item bg.
--autocomplete-highlight-colorvar(--color-background)Controls highlighted item text.
--autocomplete-icon-colorvar(--color-muted-foreground)Controls default icon color.
--autocomplete-popup-bgvar(--color-popover)Controls popup background.
--autocomplete-popup-border-colorvar(--color-border)Controls popup border color.
--autocomplete-radiusvar(--radius-md)Controls control and popup radius.
--autocomplete-shadowvar(--shadow-lg)Controls popup shadow.

Anatomy

Autocomplete combines an input field, control actions, and a popup with filtered options. Keep input-related parts together inside AutocompleteField so labeling and keyboard behavior stay connected.

Autocomplete
├─ AutocompleteField
│  ├─ AutocompleteFieldLabel
│  └─ AutocompleteInputGroup
│     ├─ AutocompleteInput
│     └─ AutocompleteControlActions (optional)
│        ├─ AutocompleteClear (optional)
│        └─ AutocompleteTrigger (optional)
└─ AutocompleteContent
   ├─ AutocompleteStatus (optional)
   ├─ AutocompleteEmpty
   ├─ AutocompleteSeparator (optional)
   └─ AutocompleteList
      ├─ AutocompleteItem
      │  └─ AutocompleteItemText
      ├─ AutocompleteRow (optional, for grid lists)
      │  └─ AutocompleteItem
      └─ AutocompleteGroup (optional)
         ├─ AutocompleteGroupLabel
         └─ AutocompleteCollection
            └─ AutocompleteItem
<Autocomplete items={tags} itemToStringValue={(item) => item.value}>
  <AutocompleteField>
    <AutocompleteFieldLabel htmlFor={id}>Search tags</AutocompleteFieldLabel>
    <AutocompleteInputGroup>
      <AutocompleteInput id={id} placeholder="e.g. feature" />
      <AutocompleteControlActions>
        <AutocompleteClear aria-label="Clear value" />
        <AutocompleteTrigger aria-label="Open suggestions" />
      </AutocompleteControlActions>
    </AutocompleteInputGroup>
  </AutocompleteField>

  <AutocompleteContent>
    <AutocompleteEmpty>No tags found.</AutocompleteEmpty>
    <AutocompleteList>
      {(item) => (
        <AutocompleteItem key={item.id} value={item}>
          <AutocompleteItemText>{item.value}</AutocompleteItemText>
        </AutocompleteItem>
      )}
    </AutocompleteList>
  </AutocompleteContent>
</Autocomplete>
PartRole
AutocompleteRoot state machine. Handles value, filtering, highlighting, and open/close behavior.
AutocompleteFieldSemantic wrapper for field-level structure. Keeps label and input wiring in one place.
AutocompleteFieldLabelAccessible label for the input or field trigger.
AutocompleteInputGroupLayout wrapper for the input and optional control actions.
AutocompleteInputText input where users type a query or free-form value.
AutocompleteControlActionsOptional container for clear/open controls.
AutocompleteClearOptional action that clears the current input value.
AutocompleteTriggerOptional action that toggles or opens the suggestion popup.
AutocompleteContentPopup surface. Also renders service slots (portal, backdrop, positioner, arrow) via props.
AutocompleteStatusOptional status region for loading or result-count feedback.
AutocompleteEmptyEmpty-state content shown when no items match.
AutocompleteListCollection container for options.
AutocompleteRowOptional row wrapper when grid is enabled on the root.
AutocompleteItemOne selectable option in the list.
AutocompleteSeparatorOptional visual separator between groups or custom sections.
AutocompleteGroupOptional grouped section with its own item subset.
AutocompleteCollectionRenderer for group items inside AutocompleteGroup.

Use default styling for service slots in most cases. Customize portal, backdrop, positioner, and arrow when you need custom layering, overlay behavior, popup placement, or arrow visuals.

Composition

Use Autocomplete for root state and Base UI behavior props such as items, value, onValueChange, filter, limit, mode, autoHighlight, and openOnInputClick.

The root keeps the Base UI behavior surface intact. Use itemToStringValue for object items, filter={null} or filteredItems for external filtering, grid with AutocompleteRow for grid navigation, modal for modal popup behavior, submitOnItemClick for single-field search forms, onOpenChange for controlled popup side effects, virtualized for externally virtualized lists, and keepHighlight or highlightItemOnHover when pointer and keyboard highlighting need custom rules. actionsRef is available for manual unmount flows with animation libraries. useAutocompleteFilter exposes Base UI string matching helpers, and useAutocompleteFilteredItems returns the currently filtered items for custom list layouts.

className styles the visible popup. classNames styles service slots hidden from the default composition: portal, backdrop, positioner, and arrow. Use container, portalProps, backdropProps, positionerProps, arrowProps, withBackdrop, and arrow when you need the matching Base UI escape hatches:

<AutocompleteContent
  className={styles.popup}
  sideOffset={8}
  withArrow
  withBackdrop
  classNames={{
    portal: styles.portal,
    backdrop: styles.backdrop,
    positioner: styles.positioner,
    arrow: styles.arrow,
  }}
/>

Examples

Grouped

Pass grouped data and render AutocompleteCollection inside each AutocompleteGroup.

import {  Autocomplete,  AutocompleteField,  AutocompleteFieldLabel,  AutocompleteInputGroup,  AutocompleteInput,  AutocompleteControlActions,  AutocompleteClear,  AutocompleteTrigger,  AutocompleteContent,  AutocompleteEmpty,  AutocompleteList,  AutocompleteGroup,  AutocompleteGroupLabel,  AutocompleteCollection,  AutocompleteItem,  AutocompleteItemText,} from "moduix";import { useId } from "react";export function GroupedAutocompleteDemo() {  const id = useId();  return (    <Autocomplete items={groupedTags} itemToStringValue={(item) => item.value}>      <AutocompleteField>        <AutocompleteFieldLabel htmlFor={id}>Search grouped tags</AutocompleteFieldLabel>        <AutocompleteInputGroup>          <AutocompleteInput id={id} placeholder="e.g. docs" />          <AutocompleteControlActions>            <AutocompleteClear aria-label="Clear value" />            <AutocompleteTrigger aria-label="Open suggestions" />          </AutocompleteControlActions>        </AutocompleteInputGroup>      </AutocompleteField>      <AutocompleteContent>        <AutocompleteEmpty>No tags found.</AutocompleteEmpty>        <AutocompleteList>          {(group) => (            <AutocompleteGroup key={group.value} items={group.items}>              <AutocompleteGroupLabel>{group.value}</AutocompleteGroupLabel>              <AutocompleteCollection>                {(item) => (                  <AutocompleteItem key={item.id} value={item}>                    <AutocompleteItemText>{item.value}</AutocompleteItemText>                  </AutocompleteItem>                )}              </AutocompleteCollection>            </AutocompleteGroup>          )}        </AutocompleteList>      </AutocompleteContent>    </Autocomplete>  );}
const groupedTags = [  {    value: "General",    items: [      { id: "gt-1", value: "feature" },      { id: "gt-2", value: "fix" },      { id: "gt-3", value: "docs" },    ],  },  {    value: "Scope",    items: [      { id: "gt-4", value: "internal" },      { id: "gt-5", value: "mobile" },      { id: "gt-6", value: "backend" },    ],  },];

Item Icons

Use item text slots for richer option content. Control icons can be replaced by passing children to AutocompleteTrigger, AutocompleteClear, or AutocompleteIcon.

import {  Autocomplete,  AutocompleteField,  AutocompleteFieldLabel,  AutocompleteInputGroup,  AutocompleteInput,  AutocompleteControlActions,  AutocompleteClear,  AutocompleteTrigger,  AutocompleteContent,  AutocompleteEmpty,  AutocompleteList,  AutocompleteItemText,  AutocompleteItemTextContent,  AutocompleteItemTextIcon,  ChevronUpIcon,  CloseLineIcon,  InfoIcon,  AutocompleteItemTextLabel,  AutocompleteItem,} from "moduix";import { useId } from "react";export function ItemIconsAutocompleteDemo() {  const id = useId();  return (    <Autocomplete items={tags} itemToStringValue={(item) => item.value}>      <AutocompleteField>        <AutocompleteFieldLabel htmlFor={id}>Search tags with icons</AutocompleteFieldLabel>        <AutocompleteInputGroup>          <AutocompleteInput id={id} placeholder="e.g. feature" />          <AutocompleteControlActions>            <AutocompleteClear aria-label="Clear value">              <CloseLineIcon />            </AutocompleteClear>            <AutocompleteTrigger aria-label="Open suggestions">              <ChevronUpIcon />            </AutocompleteTrigger>          </AutocompleteControlActions>        </AutocompleteInputGroup>      </AutocompleteField>      <AutocompleteContent>        <AutocompleteEmpty>No tags found.</AutocompleteEmpty>        <AutocompleteList>          {(item) => (            <AutocompleteItem key={item.id} value={item}>              <AutocompleteItemText>                <AutocompleteItemTextContent>                  <AutocompleteItemTextIcon>                    <InfoIcon />                  </AutocompleteItemTextIcon>                  <AutocompleteItemTextLabel>{item.value}</AutocompleteItemTextLabel>                </AutocompleteItemTextContent>              </AutocompleteItemText>            </AutocompleteItem>          )}        </AutocompleteList>      </AutocompleteContent>    </Autocomplete>  );}
const tags = [  { id: "t1", value: "feature" },  { id: "t2", value: "fix" },  { id: "t3", value: "bug" },  { id: "t4", value: "docs" },];

Input Inside Popup

Use AutocompleteFieldTrigger when the visible field opens a popup that contains the searchable input.

import {  Autocomplete,  AutocompleteField,  AutocompleteFieldLabel,  AutocompleteFieldTrigger,  AutocompleteValue,  AutocompleteIcon,  AutocompleteContent,  AutocompleteInlineInputContainer,  AutocompleteInput,  AutocompleteEmpty,  AutocompleteList,  AutocompleteItem,  AutocompleteItemText,} from "moduix";export function InputInsidePopupAutocompleteDemo() {  return (    <Autocomplete items={tags} itemToStringValue={(item) => item.value}>      <AutocompleteField>        <AutocompleteFieldLabel>Tag</AutocompleteFieldLabel>        <AutocompleteFieldTrigger>          <AutocompleteValue>{(value) => value || "Type to search"}</AutocompleteValue>          <AutocompleteIcon />        </AutocompleteFieldTrigger>      </AutocompleteField>      <AutocompleteContent>        <AutocompleteInlineInputContainer>          <AutocompleteInput placeholder="Search tag" />        </AutocompleteInlineInputContainer>        <AutocompleteEmpty>No tags found.</AutocompleteEmpty>        <AutocompleteList>          {(item) => (            <AutocompleteItem key={item.id} value={item}>              <AutocompleteItemText>{item.value}</AutocompleteItemText>            </AutocompleteItem>          )}        </AutocompleteList>      </AutocompleteContent>    </Autocomplete>  );}
const tags = [  { id: "t1", value: "feature" },  { id: "t2", value: "fix" },  { id: "t3", value: "bug" },  { id: "t4", value: "docs" },];

Limit

Set limit to cap the number of rendered matches.

import {  Autocomplete,  AutocompleteField,  AutocompleteFieldLabel,  AutocompleteInputGroup,  AutocompleteInput,  AutocompleteControlActions,  AutocompleteClear,  AutocompleteTrigger,  AutocompleteContent,  AutocompleteEmpty,  AutocompleteList,  AutocompleteItem,  AutocompleteItemText,} from "moduix";import { useId } from "react";export function LimitAutocompleteDemo() {  const id = useId();  return (    <Autocomplete      items={topMovies}      itemToStringValue={(item) => item.title}      limit={5}      openOnInputClick    >      <AutocompleteField>        <AutocompleteFieldLabel htmlFor={id}>Top 5 matches</AutocompleteFieldLabel>        <AutocompleteInputGroup>          <AutocompleteInput id={id} placeholder="Type movie title" />          <AutocompleteControlActions>            <AutocompleteClear aria-label="Clear value" />            <AutocompleteTrigger aria-label="Open suggestions" />          </AutocompleteControlActions>        </AutocompleteInputGroup>      </AutocompleteField>      <AutocompleteContent>        <AutocompleteEmpty>No movies found.</AutocompleteEmpty>        <AutocompleteList>          {(movie) => (            <AutocompleteItem key={movie.id} value={movie}>              <AutocompleteItemText>                {movie.title} ({movie.year})              </AutocompleteItemText>            </AutocompleteItem>          )}        </AutocompleteList>      </AutocompleteContent>    </Autocomplete>  );}
const topMovies = [  { id: "1", title: "The Shawshank Redemption", year: 1994 },  { id: "2", title: "The Godfather", year: 1972 },  { id: "3", title: "The Dark Knight", year: 2008 },  { id: "4", title: "Pulp Fiction", year: 1994 },  { id: "5", title: "Forrest Gump", year: 1994 },  { id: "6", title: "Inception", year: 2010 },];

Auto Highlight

Use autoHighlight="always" when the first match should be active immediately.

import {  Autocomplete,  AutocompleteField,  AutocompleteFieldLabel,  AutocompleteInputGroup,  AutocompleteInput,  AutocompleteControlActions,  AutocompleteClear,  AutocompleteTrigger,  AutocompleteContent,  AutocompleteEmpty,  AutocompleteList,  AutocompleteItem,  AutocompleteItemText,} from "moduix";import { useId } from "react";export function AutoHighlightAutocompleteDemo() {  const id = useId();  return (    <Autocomplete      items={tags}      itemToStringValue={(item) => item.value}      autoHighlight="always"      mode="list"    >      <AutocompleteField>        <AutocompleteFieldLabel htmlFor={id}>Auto highlight</AutocompleteFieldLabel>        <AutocompleteInputGroup>          <AutocompleteInput id={id} placeholder="Use arrow keys or type" />          <AutocompleteControlActions>            <AutocompleteClear aria-label="Clear value" />            <AutocompleteTrigger aria-label="Open suggestions" />          </AutocompleteControlActions>        </AutocompleteInputGroup>      </AutocompleteField>      <AutocompleteContent>        <AutocompleteEmpty>No tags found.</AutocompleteEmpty>        <AutocompleteList>          {(item) => (            <AutocompleteItem key={item.id} value={item}>              <AutocompleteItemText>{item.value}</AutocompleteItemText>            </AutocompleteItem>          )}        </AutocompleteList>      </AutocompleteContent>    </Autocomplete>  );}
const tags = [  { id: "t1", value: "feature" },  { id: "t2", value: "fix" },  { id: "t3", value: "bug" },  { id: "t4", value: "docs" },];

Grid

Enable grid and render rows manually when options should navigate as a grid.

import {  Autocomplete,  AutocompleteField,  AutocompleteFieldLabel,  AutocompleteInputGroup,  AutocompleteInput,  AutocompleteControlActions,  AutocompleteClear,  AutocompleteTrigger,  AutocompleteContent,  AutocompleteEmpty,  AutocompleteList,  AutocompleteRow,  AutocompleteItem,  AutocompleteItemText,  useAutocompleteFilteredItems,} from "moduix";import { useId } from "react";function ShortcutGrid() {  const filteredItems = useAutocompleteFilteredItems();  if (filteredItems.length === 0) {    return null;  }  return (    <AutocompleteList>      {chunkArray(filteredItems, 6).map((row) => (        <AutocompleteRow key={row.map((item) => item.id).join("-")}>          {row.map((item) => (            <AutocompleteItem key={item.id} value={item} aria-label={item.label}>              <AutocompleteItemText>{item.value}</AutocompleteItemText>            </AutocompleteItem>          ))}        </AutocompleteRow>      ))}    </AutocompleteList>  );}export function GridAutocompleteDemo() {  const id = useId();  return (    <Autocomplete      items={shortcuts}      itemToStringValue={(item) => item.label}      grid      openOnInputClick    >      <AutocompleteField>        <AutocompleteFieldLabel htmlFor={id}>Shortcut command</AutocompleteFieldLabel>        <AutocompleteInputGroup>          <AutocompleteInput id={id} placeholder="Type a command" />          <AutocompleteControlActions>            <AutocompleteClear aria-label="Clear value" />            <AutocompleteTrigger aria-label="Open suggestions" />          </AutocompleteControlActions>        </AutocompleteInputGroup>      </AutocompleteField>      <AutocompleteContent>        <AutocompleteEmpty>No shortcuts found.</AutocompleteEmpty>        <ShortcutGrid />      </AutocompleteContent>    </Autocomplete>  );}
const shortcuts = [  { id: "s1", value: "N", label: "New file" },  { id: "s2", value: "O", label: "Open file" },  { id: "s3", value: "S", label: "Save file" },  { id: "s4", value: "P", label: "Print" },  { id: "s5", value: "F", label: "Find" },  { id: "s6", value: "R", label: "Replace" },];function chunkArray(items, size) {  const chunks = [];  for (let index = 0; index < items.length; index += size) {    chunks.push(items.slice(index, index + size));  }  return chunks;}

Fuzzy

Provide a custom filter when matching should differ from the default string comparison.

import {  Autocomplete,  AutocompleteField,  AutocompleteFieldLabel,  AutocompleteInputGroup,  AutocompleteInput,  AutocompleteControlActions,  AutocompleteClear,  AutocompleteTrigger,  AutocompleteContent,  AutocompleteEmpty,  AutocompleteList,  AutocompleteItem,  AutocompleteItemText,} from "moduix";import { useId } from "react";export function FuzzyAutocompleteDemo() {  const id = useId();  return (    <Autocomplete      items={topMovies}      itemToStringValue={(item) => item.title}      filter={(item, query, itemToString) => {        const label = itemToString ? itemToString(item) : String(item);        return isFuzzyMatch(label, query);      }}    >      <AutocompleteField>        <AutocompleteFieldLabel htmlFor={id}>Fuzzy search</AutocompleteFieldLabel>        <AutocompleteInputGroup>          <AutocompleteInput id={id} placeholder="e.g. tdk or sra" />          <AutocompleteControlActions>            <AutocompleteClear aria-label="Clear value" />            <AutocompleteTrigger aria-label="Open suggestions" />          </AutocompleteControlActions>        </AutocompleteInputGroup>      </AutocompleteField>      <AutocompleteContent>        <AutocompleteEmpty>No movies found.</AutocompleteEmpty>        <AutocompleteList>          {(movie) => (            <AutocompleteItem key={movie.id} value={movie}>              <AutocompleteItemText>                {movie.title} ({movie.year})              </AutocompleteItemText>            </AutocompleteItem>          )}        </AutocompleteList>      </AutocompleteContent>    </Autocomplete>  );}
const topMovies = [  { id: "1", title: "The Shawshank Redemption", year: 1994 },  { id: "2", title: "The Godfather", year: 1972 },  { id: "3", title: "The Dark Knight", year: 2008 },  { id: "4", title: "Pulp Fiction", year: 1994 },];function isFuzzyMatch(value, query) {  const normalizedValue = value.toLowerCase().trim();  const normalizedQuery = query.toLowerCase().trim();  if (normalizedQuery === "") {    return true;  }  let queryIndex = 0;  for (const character of normalizedValue) {    if (character === normalizedQuery[queryIndex]) {      queryIndex += 1;      if (queryIndex === normalizedQuery.length) {        return true;      }    }  }  return false;}

Control value, disable the built-in filter with filter={null}, and keep AutocompleteStatus mounted while its children change.

import {  Autocomplete,  AutocompleteField,  AutocompleteFieldLabel,  AutocompleteInputGroup,  AutocompleteInput,  AutocompleteControlActions,  AutocompleteClear,  AutocompleteTrigger,  AutocompleteContent,  AutocompleteStatus,  AutocompleteEmpty,  AutocompleteList,  AutocompleteItem,  AutocompleteItemText,  useAutocompleteFilter,} from "moduix";import { useId, useRef, useState, useTransition } from "react";export function AsyncSearchAutocompleteDemo() {  const id = useId();  const { contains } = useAutocompleteFilter();  const [value, setValue] = useState("");  const [searchResults, setSearchResults] = useState([]);  const [isPending, startTransition] = useTransition();  const abortControllerRef = useRef(null);  const trimmedValue = value.trim();  const status = isPending    ? "Searching..."    : trimmedValue !== "" && searchResults.length === 0      ? `No matches for "${trimmedValue}".`      : null;  return (    <Autocomplete      items={searchResults}      value={value}      filter={null}      itemToStringValue={(item) => item.title}      onValueChange={(nextValue) => {        setValue(nextValue);        const controller = new AbortController();        abortControllerRef.current?.abort();        abortControllerRef.current = controller;        if (nextValue.trim() === "") {          setSearchResults([]);          return;        }        startTransition(async () => {          await new Promise((resolve) => setTimeout(resolve, 250));          if (controller.signal.aborted) {            return;          }          setSearchResults(            topMovies.filter(              (movie) =>                contains(movie.title, nextValue) ||                contains(movie.year.toString(), nextValue),            ),          );        });      }}    >      <AutocompleteField>        <AutocompleteFieldLabel htmlFor={id}>          Search movies by name or year        </AutocompleteFieldLabel>        <AutocompleteInputGroup>          <AutocompleteInput id={id} placeholder="e.g. Pulp Fiction or 1994" />          <AutocompleteControlActions>            <AutocompleteClear aria-label="Clear value" />            <AutocompleteTrigger aria-label="Open suggestions" />          </AutocompleteControlActions>        </AutocompleteInputGroup>      </AutocompleteField>      <AutocompleteContent>        <AutocompleteStatus>{status}</AutocompleteStatus>        <AutocompleteEmpty>          {trimmedValue !== "" && !isPending ? "Try a different query." : null}        </AutocompleteEmpty>        <AutocompleteList>          {(movie) => (            <AutocompleteItem key={movie.id} value={movie}>              <AutocompleteItemText>                {movie.title} ({movie.year})              </AutocompleteItemText>            </AutocompleteItem>          )}        </AutocompleteList>      </AutocompleteContent>    </Autocomplete>  );}
const topMovies = [  { id: "1", title: "The Shawshank Redemption", year: 1994 },  { id: "2", title: "The Godfather", year: 1972 },  { id: "3", title: "The Dark Knight", year: 2008 },  { id: "4", title: "Pulp Fiction", year: 1994 },];

Custom Styles

Style the popup directly with className and service slots with classNames.

import {  Autocomplete,  AutocompleteField,  AutocompleteFieldLabel,  AutocompleteInputGroup,  AutocompleteInput,  AutocompleteControlActions,  AutocompleteClear,  AutocompleteTrigger,  AutocompleteContent,  AutocompleteEmpty,  AutocompleteList,  AutocompleteItem,  AutocompleteItemText,} from "moduix";import { useId } from "react";export function CustomStylesAutocompleteDemo() {  const id = useId();  return (    <Autocomplete items={tags} itemToStringValue={(item) => item.value}>      <AutocompleteField>        <AutocompleteFieldLabel htmlFor={id}>Search tags</AutocompleteFieldLabel>        <AutocompleteInputGroup>          <AutocompleteInput id={id} placeholder="e.g. feature" />          <AutocompleteControlActions>            <AutocompleteClear aria-label="Clear value" />            <AutocompleteTrigger aria-label="Open suggestions" />          </AutocompleteControlActions>        </AutocompleteInputGroup>      </AutocompleteField>      <AutocompleteContent        className={styles.customPopup}        sideOffset={8}        withArrow        withBackdrop        classNames={{          portal: styles.customPortal,          backdrop: styles.customBackdrop,          positioner: styles.customPositioner,          arrow: styles.customArrow,        }}      >        <AutocompleteEmpty>No tags found.</AutocompleteEmpty>        <AutocompleteList>          {(item) => (            <AutocompleteItem key={item.id} value={item}>              <AutocompleteItemText>{item.value}</AutocompleteItemText>            </AutocompleteItem>          )}        </AutocompleteList>      </AutocompleteContent>    </Autocomplete>  );}
.customPortal {  position: relative;}.customPositioner {  --autocomplete-popup-max-height: 18rem;}.customPopup {  --autocomplete-popup-bg: color-mix(in srgb, var(--color-popover) 92%, var(--color-primary));  --autocomplete-popup-border-color: color-mix(in srgb, var(--color-border) 72%, var(--color-primary));  --autocomplete-shadow: var(--shadow-md);}.customBackdrop {  --autocomplete-backdrop-bg: var(--color-overlay);  --autocomplete-backdrop-blur: 2px;}.customArrow {  --autocomplete-arrow-stroke-color: var(--color-border);}
const tags = [  { id: "t1", value: "feature" },  { id: "t2", value: "fix" },  { id: "t3", value: "bug" },  { id: "t4", value: "docs" },];

On this page