Skip to content

Repository files navigation

forty-cdk

Headless, styleless UI primitives for modern Angular — accessibility built in.

npm version CI License: MIT Angular

Documentation · accessible · zoneless · SSR-safe · tree-shakable


forty-cdk exposes the state, behavior, focus management, and keyboard interaction of each component; you bring your own styles. Every primitive is designed from the ground up for modern Angular — the API is built around signals, standalone directives, and dependency-injection composition.

Why forty-cdk

♿  Accessibility is the API — every primitive implements a WAI-ARIA APG pattern: roles, keyboard, focus management, RTL. 🎨  Styleless — you get behavior and state; style against your own class, data-* state attributes and --for-* custom properties.
⚡  Modern Angular — signal / computed / input() / model(), standalone directives and DI composition throughout. 🌳  Tree-shakable — one secondary entry point per primitive; your bundle ships only what you import.
🚫  Zoneless — works under provideZonelessChangeDetection(). No Zone.js, ever. 🖥️  SSR-safe — every primitive is covered by a server-render smoke test.

Installation

npm install forty-cdk

Requires @angular/common and @angular/core ^22.0.1. Some primitives have optional peers (@angular/forms, @internationalized/date) — see the peer dependency reference.

Quick start

Every primitive is a set of standalone directives you compose in your own markup. Import from the per-primitive entry point, add the for* directive, style against the reflected data-* state:

import { Component, signal } from '@angular/core';
import { ForSwitch } from 'forty-cdk/switch';

@Component({
  selector: 'demo-toggle',
  imports: [ForSwitch],
  template: `
    <button forSwitch class="switch" [(checked)]="enabled">
      <span class="thumb"></span>
    </button>
  `,
})
export class DemoToggle {
  readonly enabled = signal(false);
}
.switch .thumb {
  transition: transform 150ms;
}
.switch[data-state='checked'] .thumb {
  transform: translateX(100%);
}

New to the composition model? Your first overlay walks one Popover from empty markup to styled-and-animated.

What's inside

Accessible primitives grouped by purpose. See the full catalog with descriptions » — each links to its own README with anatomy, API, keyboard map and styling hooks.

  • Overlays — Dialog, Drawer, Popover, Hover Card, Tooltip, Toast
  • Menus — Menu, Dropdown Menu, Context Menu, Menubar
  • Navigation — Navigation Menu, Breadcrumbs, Pagination, Tabs, Toolbar, Stepper
  • Forms & input — Button, Field, Fieldset, Input, Search, Number Input, OTP Input, File Upload, Switch, Checkbox, Toggle, Radio Group, Slider, Select, Combobox, Listbox
  • Date & time — Calendar, Date Field, Date Picker, Time Field, Time Picker
  • Disclosure & content — Accordion, Disclosure, Carousel
  • Data & layout — Table, Tree, Scroll Area, Pane Resizer, Separator, Aspect Ratio, Avatar, Visually Hidden
  • Feedback — Progress, Meter
  • Utilities — Breakpoints, Drag & Drop, Virtualization, Table Virtualization, Virtual Reorder

Documentation

  • Documentation site — every primitive with live, editable examples.
  • llms.txt — the documentation as markdown, for AI assistants: an llmstxt.org index over one clean .md per page, each published at that page's own URL plus .md (so /select is also /select.md). Point your assistant at the page it needs — the root package name exports nothing, and that is the fact a model guesses wrong.
  • Library README — installation, peer dependencies and the full primitive catalog.
  • Your first overlay — one Popover from empty markup to styled-and-animated, explaining the @if / open-state model and the portal → global CSS requirement every overlay shares.
  • Styling forty-cdk — the three hooks you style against: your own class, data-* state attributes, and --for-* custom properties.
  • docs/ — the remaining guides (styling floating content, the selection value-type contract, wrapping primitives in a design system, the Table layers).
  • CHANGELOG — release notes.

Development

This is an Angular CLI workspace with the forty-cdk library plus two dev-only apps: forty-cdk-harness (drives the Playwright E2E suite) and forty-cdk-docs (the documentation site, deployed to GitHub Pages). The repo uses pnpm, pinned via Corepack.

pnpm build        # ng build forty-cdk (production, ng-packagr → dist/forty-cdk)
pnpm watch        # rebuild the library on change
pnpm test         # unit tests (Vitest + jsdom), pinned to the library project
pnpm test:e2e     # playwright test (Chromium + WebKit; spins up the harness)
pnpm lint         # eslint (flat config)
pnpm typecheck    # library + both apps
pnpm format       # prettier --write .
pnpm docs         # serve the documentation site locally

A lefthook pre-commit hook lints and formats the staged files and runs the library typecheck; it installs itself when pnpm install runs the prepare script. Bypass it for a one-off commit with git commit --no-verify. CI additionally runs pnpm format:check, the full pnpm typecheck, and the E2E suite sharded across both engines.

License

MIT

About

Headless / styleless UI primitives for Angular with WAI-ARIA accessibility built in

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages