Headless checkbox
Headless checkbox keeps the native <input type="checkbox"> element in place and adds a consistent state contract for checked, mixed, readonly, invalid, and keyboard-focus styling.
- Binary and tri-state behavior with
checkedandindeterminate. - Readonly support that keeps the control focusable while reverting user toggles.
- Stable
data-*hooks for custom visuals without wrapper lock-in.
Installation
Import only the checkbox primitive when your app already owns the surrounding markup.
Primitive import
ts
import { TngCheckbox } from '@tailng-ui/primitives';
Basic usage
The directive can live on a bare input, but in practice you usually wrap it in a <label> so the text stays clickable and supplies the accessible name.
Minimal attachment
html
<input tngCheckbox />
Recommended labeled pattern
html
<label class="headless-checkbox-row">
<input tngCheckbox [checked]="true" />
<span>Email release updates</span>
</label>
Tri-state example
html
<label class="headless-checkbox-row">
<input
tngCheckbox
[indeterminate]="true"
[ariaDescribedBy]="'selection-help'"
/>
<span>Deployment checklist (mixed)</span>
</label>
<p id="selection-help">One or more child checks are still pending.</p>
Style variants
Same headless checkbox behavior rendered inside a plain CSS shell and a Tailwind utility shell.
Headless checkbox stack (Plain-CSS)
Headless checkbox stack (Tailwind CSS)
Accessibility baseline
aria-checkedresolves totrue,false, ormixed.readonlykeeps the native checkbox in the tab order.data-focus-visiblemakes keyboard-only focus styling straightforward.