Scalability of Angular. Simplicity of Tailwind.
A modern Angular 21+ component system built with Signals, Standalone APIs, and strict architectural discipline.
TailNG is an open-source Angular component system designed for:
- Large applications
- Enterprise design systems
- Strict type safety
- Accessibility-first development
- Signal-based architecture
- Tailwind-compatible styling
It combines:
- Angular 21+
- Standalone Components
- Angular Signals
- Strict ESLint architecture
- Nx monorepo discipline
- Optional Tailwind integration
TailNG is evolving toward a framework-agnostic component platform with:
- Accessibility-first primitives built on Angular CDK and
@angular/aria(experimental) - Wrapper abstractions that make component composition simpler for app developers
- Additional in-house components implemented using ARIA authoring principles
- Micro-level styling control for each component (slots, states, tokens, and hooks)
- No required dependency on Tailwind or any specific CSS framework
- Zero hard coupling between component behavior and styling systems
- Shadcn-style copy/paste distribution mode in addition to package install
- Primary path: use
@angular/ariaas the basis for new primitives - Current tradeoff: accept experimental risk while Angular 22 direction matures
- Fallback policy: do not build full CDK fallback now
- Constraint: keep an adapter seam now so fallback can be implemented later without rewrites
- Rule: components depend on TailNG primitive contracts, not direct
@angular/ariaimports
| Package | Description |
|---|---|
@tailng-ui/ui |
Main component library |
@tailng-ui/cdk |
Behavior primitives & utilities |
@tailng-ui/theme |
Design tokens & Tailwind adapter |
@tailng-ui/icons |
Icon wrappers |
pnpm add @tailng-ui/uiPeer dependencies:
@angular/core^21@angular/common^21@angular/forms^21
import { Component } from '@angular/core';
import { TngButton } from '@tailng-ui/ui';
@Component({
standalone: true,
imports: [TngButton],
template: `
<tng-button variant="primary">
Click me
</tng-button>
`,
})
export class ExampleComponent {}TailNG follows a layered structure:
apps/ docs/ → Documentation site playground/ → Component sandbox
libs/ ui/ → Styled components cdk/ → Behavior primitives theme/ → Tokens & adapters icons/ → Icon library
Design principles:
- Composition over prop explosion
- Behavior separated from styling
- Strict architectural boundaries (Nx enforced)
- Public API discipline
- No deep imports
- Exhaustive state safety
TailNG is:
- Headless-friendly
- Tailwind-compatible (not required)
- Accessibility-aware
- Strictly typed
- Enterprise-ready
- Open-source forever (MIT)
We aim to provide:
- Clean APIs
- Predictable behavior
- Scalable structure
- Zero vendor lock-in
pnpm installpnpm playgroundRun registry CLI playground:
pnpm dev:registrypnpm docsBuild static output for Cloudflare Pages:
pnpm docs:seoBuild static playground output for Cloudflare Pages:
pnpm playground:seoBuild static vanilla playground output for Cloudflare Pages:
pnpm playground:vanilla:seopnpm nx run-many -t lintpnpm testRun all library tests directly with Nx:
pnpm test:nxRun only theme tests:
pnpm test:themeRun CLI integration tests (tailng add ... end-to-end in temp directories):
pnpm test:cliRun in watch mode:
pnpm nx run theme:vite:test --watchRun with coverage:
pnpm nx run theme:vite:test --coverageRun directly with Vitest (without Nx):
pnpm exec vitest run --config libs/tailng-ui/theme/vitest.config.tsBuild and run the tailng CLI:
pnpm build:tailng
pnpm tailng -- list
pnpm tailng -- add button --cwd apps/tailng-ui/playground-vanilla --dry-run
pnpm tailng -- add button --cwd apps/tailng-ui/playground-registry --dry-runRegistry command reference:
- List available registry items:
pnpm tailng -- list- Preview file generation without writing:
pnpm tailng -- add button --cwd apps/tailng-ui/playground-registry --dry-run- Generate files:
pnpm tailng -- add button --cwd apps/tailng-ui/playground-registry- Overwrite existing generated files:
pnpm tailng -- add button --cwd apps/tailng-ui/playground-registry --forceNote:
--dry-runshowsCREATE,SKIP, orOVERWRITEbehavior.--cwdshould point to the app root where files must be generated.tailng add buttonfollows shadcn-style source copy. It writes local files to:src/app/tailng-ui/button/tng-button-primitive.tssrc/app/tailng-ui/button/tng-button.tssrc/app/tailng-ui/button/tng-button.htmlsrc/app/tailng-ui/button/tng-button.csssrc/app/tailng-ui/button/index.ts
- Import locally in your app:
import { TngButton } from './tailng-ui/button';- Use Angular Signals (
input()) - Standalone components only
- No default exports
- Explicit return types
- Exhaustive switch checks
- Complexity ≤ 8
- Max params ≤ 3
- Accessibility-first markup
- Strict ESLint enforced
- Website: https://tailng.dev
- npm: https://www.npmjs.com/package/@tailng-ui/ui
- GitHub: https://github.com/tailng/tailng-ui
Contributions are welcome.
Before submitting a PR:
- Follow ESLint rules
- Respect architectural boundaries
- Avoid deep imports
- Maintain strict typing
- Include playground demo
MIT © 2026 TailNG