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

Imports

Primitive imports

ts
import {
  TngMultiSelect,
  TngMultiSelectListbox,
  TngMultiSelectOption,
  TngSelectContent,
  TngSelectIcon,
  TngSelectOverlay,
  TngSelectTrigger,
  TngSelectValue,
} from '@tailng-ui/primitives';

Basic usage

Owned multiselect composition

html
<section
  tngMultiSelect
  [value]="selectedPlanets()"
  (valueChange)="onValueChange($event)"
>
  <button type="button" tngSelectTrigger>
    <span tngSelectValue>{{ selectedSummary() }}</span>
    <span tngSelectIcon aria-hidden="true">▾</span>
  </button>

  <div tngSelectContent>
    <div tngSelectOverlay>
      <ul
        tngMultiSelectListbox
        [multiple]="true"
        [value]="selectedPlanets()"
      >
        @for (planet of planets; track planet.value) {
          <li tngMultiSelectOption [tngValue]="planet.value">{{ planet.label }}</li>
        }
      </ul>
    </div>
  </div>
</section>

MultiSelect variants

The same headless multiselect primitive rendered with an owned plain-CSS shell and a light Tailwind shell.

Planets (Plain-CSS)

Planets

Primitive-first multi-selection with an owned trigger and owned overlay rows.

Selected: Earth, Mars

Behavior baseline

  • The trigger owns combobox semantics, focus, and aria-expanded.
  • The multiselect listbox keeps active option state and selected values in sync.
  • Enter toggles the active option without closing the overlay.
  • Values are modelled as readonly T[] and emitted as arrays on every toggle.
  • Use data-active, data-selected, and data-disabled for option state styling.