Headless — Quick Start
TailNG headless components are behavior-only primitives: they handle accessibility, keyboard and pointer behavior, and state while you own the markup and styling.
Quick Start
Create a first headless-driven page with keyboard-safe interaction defaults.
What is Headless?
Primitives live in @tailng-ui/primitives and expose interaction behavior through directives and data attributes (for example tngCheckbox, tngToggle, tngAccordion).
Styled components in @tailng-ui/components are built on these primitives. You can use them directly or copy and own source via CLI.
1. Install TailNG
Option A — Primitives only (headless)
pnpm
pnpm add @tailng-ui/primitives @tailng-ui/cdk
npm
npm install @tailng-ui/primitives @tailng-ui/cdk
yarn
yarn add @tailng-ui/primitives @tailng-ui/cdk
If you are building headless UI only, this is the required runtime install.
Option B — Full set (headless + styled + theme + icons)
pnpm
pnpm add @tailng-ui/components @tailng-ui/primitives @tailng-ui/cdk @tailng-ui/theme @tailng-ui/icons
npm
npm install @tailng-ui/components @tailng-ui/primitives @tailng-ui/cdk @tailng-ui/theme @tailng-ui/icons
yarn
yarn add @tailng-ui/components @tailng-ui/primitives @tailng-ui/cdk @tailng-ui/theme @tailng-ui/icons
@tailng-ui/cdk is required by headless primitives. Add @tailng-ui/theme if you use TailNG theme tokens, and @tailng-ui/icons if you use the icon set.
2. Include components in your project
You do not need to install @tailng-ui/registry directly. The registry package is consumed by the tailng CLI for copy/source workflows.
Option A — Copy source into your app (shadcn-style, ownable)
Use tailng list to inspect the supported ownable registry items for the current package version before running tailng add.
CLI setup
# Install CLI (once)
pnpm add -D tailng
# Or run without installing
pnpm dlx tailng add button
npx tailng add button
Add components
tailng add <component-name>
tailng add button
tailng add checkbox
tailng add accordion
tailng add tooltip
tailng add drawer
CLI options
--cwd <path> # App root where files are generated (default: current directory)
--dry-run # Show what would be created without writing files
--force # Overwrite existing generated files
tailng add button --cwd apps/my-app
tailng add dialog --dry-run
tailng add checkbox --force
Import generated source
import { TngButton } from './tailng-ui/button';
Option B — Use npm packages directly
Import primitives (and optionally styled components) from package exports and register them in standalone components or NgModules.
Direct package imports
import { TngCheckbox, TngToggle } from '@tailng-ui/primitives';
// optional styled components
import { TngCheckboxComponent, TngButtonComponent } from '@tailng-ui/components';
3. Example: using headless primitives
Checkbox (headless)
import { Component, signal } from '@angular/core';
import { TngCheckbox } from '@tailng-ui/primitives';
@Component({
imports: [TngCheckbox],
template: `
<label>
<input
type="checkbox"
tngCheckbox
[checked]="checked()"
(checkedChange)="checked.set($event)"
/>
<span>Accept terms</span>
</label>
`,
})
export class MyForm {
checked = signal(false);
}
Toggle (headless)
import { Component, signal } from '@angular/core';
import { TngToggle } from '@tailng-ui/primitives';
@Component({
imports: [TngToggle],
template: `
<button
type="button"
tngToggle
[pressed]="on()"
(pressedChange)="on.set($event)"
>
Toggle
</button>
`,
})
export class MyToolbar {
on = signal(false);
}
Accordion (headless)
import { Component, signal } from '@angular/core';
import {
TngAccordion,
TngAccordionItem,
TngAccordionTrigger,
TngAccordionPanel,
} from '@tailng-ui/primitives';
@Component({
imports: [TngAccordion, TngAccordionItem, TngAccordionTrigger, TngAccordionPanel],
template: `
<section
tngAccordion
type="single"
[value]="open()"
(valueChange)="open.set($event)"
>
<article tngAccordionItem value="a">
<button tngAccordionTrigger>Section A</button>
<div tngAccordionPanel>Content A</div>
</article>
<article tngAccordionItem value="b">
<button tngAccordionTrigger>Section B</button>
<div tngAccordionPanel>Content B</div>
</article>
</section>
`,
})
export class MyAccordion {
open = signal<string | null>('a');
}
Style via data attributes (for example [data-state="open"], [data-checked]) or your own classes.
4. Theme (optional)
If you use @tailng-ui/theme, register provideTailngTheme() in your app configuration.
app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideTailngTheme } from '@tailng-ui/theme';
export const appConfig: ApplicationConfig = {
providers: [
provideTailngTheme(),
],
};
5. CLI component aliases
| You write | Resolves to |
|---|---|
| slide-toggle | switch |
| sidenav / sidebar / sheet | drawer |
| expansion-panel | accordion |
| spinner | progress-spinner |
| snackbar / sonner | toast |
6. List available components
Use this command to see all valid values for tailng add <component-name>. The command output is the source of truth for the current registry surface.
List components
tailng list
pnpm dlx tailng list