Getting StartedInstall and bootstrap headless foundations 4
LayoutHeadless structural primitives for expandable and container patterns 6
OverlayHeadless modal and floating layer behavior 3
FeedbackHeadless notification and status communication patterns 5
FormHeadless input and selection contracts 17
UtilityReusable action, identity, and clipboard behavior 6
NavigationHeadless trails, trees, menus, and command surfaces 7

What you get

Headless autocomplete gives you a combobox-style query + option-selection contract without forcing a wrapper DOM shape. You own the trigger, icon, content shell, overlay shell, and option rendering.

  • Single-value selection with keyboard-safe combobox semantics.
  • Separate query and value state, so filtering and selection stay distinct.
  • Owned parts for trigger, icon, content, overlay, listbox, and options.
  • Free-form create support when allowCreate is enabled.

Installation

Import the primitive root and the owned parts you plan to render.

Autocomplete primitive imports

ts
import {
  TngAutocomplete,
  TngAutocompleteTrigger,
  TngAutocompleteTriggerContainer,
  TngAutocompleteIcon,
  TngAutocompleteContent,
  TngAutocompleteOverlay,
  TngAutocompleteListbox,
  TngAutocompleteOption,
} from '@tailng-ui/primitives';

Basic usage

The primitive root owns selection, open state, invalid/loading state, and query/create behavior. Your trigger and overlay markup remain native.

Basic headless autocomplete

html
<section
  tngAutocomplete
  [open]="open()"
  (openChange)="open.set($event)"
  [value]="selectedCountry()"
  (valueChange)="selectedCountry.set($event)"
  [query]="query()"
  (queryChange)="query.set($event)"
>
  <div tngAutocompleteTriggerContainer>
    <input
      tngAutocompleteTrigger
      type="text"
      [value]="displayText()"
      (input)="onInput($event)"
      aria-label="Country directory"
      placeholder="Search countries"
    />
    <span tngAutocompleteIcon aria-hidden="true">▾</span>
  </div>

    <div tngAutocompleteContent class="contents">
    <div tngAutocompleteOverlay>
      <ul tngAutocompleteListbox [value]="selectedCountry()">
        @for (country of filteredCountries(); track country.code) {
          <li tngAutocompleteOption [tngValue]="country.code">{{ country.label }}</li>
        }
      </ul>
    </div>
  </div>
</section>

Style variants

The same primitive structure can sit inside a plain CSS shell or a Tailwind utility shell.

Country directory (Plain-CSS)

Country directory

Selected: India

Accessibility baseline

  • The trigger stays a real input with role="combobox" applied by the primitive.
  • The list uses listbox/option semantics and active option tracking through aria-activedescendant.
  • Tab leaves the combobox; arrow keys and Enter stay inside the autocomplete interaction model.
  • aria-labelledby, aria-describedby, and invalid/error wiring come from the primitive root inputs.