Getting Started
kouji-ui is a headless Angular 22 UI library. The core is behaviour — bring your own styles, or add the themed components.
Installation
Two paths — pick one, mix as you grow.
Styled
Drop-in ready. Behaviour, styled wrappers, and the 13 themes. Pick a theme with [data-theme="kouji"] on <html> and ship.
Headless
Just the behaviour layer. Directives expose ARIA semantics and data-* hooks; you bring the CSS (Tailwind, design tokens, plain stylesheets — anything).
Angular 22+ only. Standalone components, signals throughout. No Angular CDK and no third-party UI runtime — the only required peers are @angular/* and rxjs.
Global stylesheets
Register these once in angular.json. @kouji-ui/core/styles.css is the core's one global stylesheet — overlay chrome, the [kjIcon] mask, .kj-prose typography and the kjMotion presets. Together with the components overlay.css it is the only thing that paints every floating panel — popover, tooltip, dropdown menu, dialog, drawer, toast, confirm popup, sheet. The wrapper components carry no styleUrl of their own, so omitting overlay.css leaves every panel unstyled.
On Vite or Analog there is no angular.json: import the same three files by package specifier from your global stylesheet. Every path is declared in the packages' exports maps, so bundlers that enforce them resolve it.
Prefer à la carte? The core aggregate is exactly these four files, each published on its own:
Overlay panels need these. Every panel is rendered by a headless directive (<kj-popover-content>, <kj-dropdown-menu-content>, …), and directives carry no styles. Skip the overlay stylesheets and a panel composed straight from the directives comes up with no background, no border and no shadow — even though the markup is correct. Wrapper components such as <kj-popover> inline the same CSS, so a page that happens to render one looks fine while the rest do not.
Vite / Analog
There is no angular.json outside the Angular CLI, so the three global stylesheets are imported by package specifier from your own global stylesheet (see Global stylesheets above), and that stylesheet is imported once from the app entry.
Nothing else is needed in vite.config.ts. Both packages ship pure-ESM FESM2022 with "sideEffects": false, no CommonJS interop and no module-scope document / window access, so Vite externalizes them for SSR without ssr.noExternal.
Optional peers
Only the @angular/* packages and rxjs are required. Everything heavy — ECharts, Monaco, Lexical, TanStack Virtual, Lucide — is an optional peer reached through a dynamic import() or an import type, so a bare import '@kouji-ui/core' resolves in plain Node with none of them installed.
Quick start
Import directive directly — no NgModules needed.
Headless usage
The core package ships no component styles. Directives add ARIA attributes and data-* attributes you can target in your stylesheets:
Angular forms
Form controls compose KjFormControl via hostDirectives, so they work with reactive forms out of the box:
Accessibility
Every component targets WCAG 2.1 AAA. Keyboard interactions, ARIA patterns, and focus management are baked into the headless primitives.
Use the a11y utilities to enhance your own components:
All overlay components (Dialog, Menu, Select) compose KjFocusTrap, KjRovingTabindex, and KjLiveRegion from @kouji-ui/core for full keyboard + screen-reader support — verified against NVDA, JAWS, and VoiceOver.