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

Headless switch

Headless switch keeps the interaction surface as a real <button> with role="switch". You own the surrounding layout, the thumb markup, and the label treatment while TailNG provides the checked, disabled, and focus-visible state contract.

  • checked and data-state stay in sync for visual and ARIA state.
  • disabled blocks interaction and exposes a clean styling hook.
  • ariaLabel gives the switch an accessible name when visible text lives outside the button.

Installation

Import the primitive when you want TailNG to own only the switch semantics.

Primitive import

ts
import { TngSwitch } from '@tailng-ui/primitives';

Basic usage

The primitive attaches to button[tngSwitch]. When the visible copy is separate from the button, provide ariaLabel so screen readers hear the same label.

Minimal attachment

html
<button
  tngSwitch
  [checked]="releaseReady()"
  ariaLabel="Release ready"
  (click)="releaseReady.update(value => !value)"
>
  <span class="switch-thumb" aria-hidden="true"></span>
</button>

Recommended labeled row

html
<div class="headless-switch-row">
  <button
    tngSwitch
    class="headless-switch-row__control"
    [checked]="releaseReady()"
    ariaLabel="Release ready"
    (click)="releaseReady.update(value => !value)"
  >
    <span class="headless-switch-row__thumb" aria-hidden="true"></span>
  </button>
  <div class="headless-switch-row__copy">
    <span class="headless-switch-row__title">Release ready</span>
    <span class="headless-switch-row__meta">Ship after QA sign-off.</span>
  </div>
</div>

Style variants

The same primitive switch behavior can sit inside a plain CSS shell or a Tailwind utility shell without changing the API.

Release switch shell (Plain-CSS)

Release readyShip after QA sign-off.

Accessibility baseline

  • role="switch" and aria-checked are handled by the directive.
  • Use ariaLabel whenever the visible copy is not inside the button itself.
  • The primitive keeps keyboard focus on the button, so :focus-visible styles stay simple.