@xngui/styles
v0.0.5
Published
Design tokens and generic state styles for @xngui
Readme
@xngui/styles
Foundation CSS: primitives → semantic → scale → field → states → scrollbar. Optional Tailwind + base. No per-component skins — shared field tokens only.
Install
pnpm add @xngui/stylesImport once in your app global stylesheet:
@import '@xngui/styles';
@import '@xngui/icons/fontawesome'; /* when using <x-icon> */Pair with @xngui/theme for runtime appearance and palette presets. See the Styles docs and Themes docs.
Token contract
- Consume semantic tokens in components (
--x-primary,--x-danger-hover, …). Prefer not to invent colors withcolor-mix/ hardcoded oklch. - Primitives (
--x-primary-700,--x-spacing-4) are for one-offs and semantic bindings — not everyday component CSS. - Scale (
scale/) — orthogonal size tier + density + resolved--x-control-*on[data-size]hosts. - Component tokens (
--x-button-*) alias semantics or resolved scale; legacy--x-control-height-*aliases--x-size-height-*. - Field tokens (
--x-field-*infield.css) are the shared form-control recipe; form components alias them. Looks via[data-look](outline|fill|flat|none). - Never re-export Tailwind hue palettes (red/blue/slate) from this package.
When to use which slot
| Appearance | Fill | Hover / active | Text / icon |
| ---------- | --------------------------------- | ------------------------------------- | ----------------------- |
| Solid | --x-{role} | --x-{role}-hover / -active | --x-{role}-foreground |
| Outline | transparent + --x-{role}-border | --x-{role}-subtle / -subtle-hover | --x-{role} |
| Soft | --x-{role}-subtle | -subtle-hover / -subtle-active | --x-{role} |
| Ghost | transparent | subtle or muted hover | role or foreground |
Secondary vs neutral
| Role | Meaning | | ------------- | ---------------------------------------------------------------------- | | neutral | Achromatic page chrome — background, border, muted, card | | secondary | Cool slate — quiet actions / secondary buttons (not page surfaces) |
Pipeline
Primitive Tokens libs/styles/primitives/* raw oklch role ramps + structural scales
|
v
Semantic Tokens libs/styles/semantic/* roles bound to steps (--x-primary -> --x-primary-700)
|
v
Theme Overrides libs/styles/semantic/dark.css + @xngui/theme (XThemeService)
same semantic vars, remapped under `.dark`
|
v
Control Scale libs/styles/scale/* size tier + density offsets + --x-control-* resolved
|
v
Tailwind Utilities libs/styles/tailwind/* `@theme inline` → `bg-primary`, `bg-primary-subtle`
|
v
Angular Components libs/components/**/*-tokens.css `--x-button-*` aliasesLayout
libs/styles/
primitives/ # color, space, typography, radius, motion, interaction affordances, icon
semantic/
light.css # :root theme roles
dark.css # .dark remaps
index.css
scale/ # size tier, density offsets, resolved --x-control-* (orthogonal to states)
size.css
density.css
resolved.css
index.css
field.css # shared form-field tokens + look recipes
states/ # opt-in interactive looks (disabled, focus, invalid, …)
scrollbar.css # thin theme-aware scrollbars (loaded from index)
base.css # optional CSS reset
tailwind/ # @theme map + Tailwind entry
themes/ # 17 chromatic hues + 12 semantic themes
index.cssControl scale (size + density)
Size (xs–xl) sets visual tier: height base, typography, inline icon, radius, pad/gap bases.
Density (compact / comfortable / standard) applies spacing offsets only — never compresses type or icons.
| Layer | Tokens | Set on |
| --------- | ------------------------------------------------- | ----------------------------------------------- |
| Size tier | --x-size-height-*, --x-size-font-*, … | :root |
| Density | --x-density-offset-* | [data-density] (inherits to children) |
| Resolved | --x-control-height, --x-control-pad-inline, … | [data-size] host |
| Radius | --x-scale-radius, --x-control-radius | [data-size='…'] tier only — never density |
Formula: H(s) = 2.5rem + 0.5rem × index (md = 40px). Density: ±4px on height/padding.
/* Component recipe */
.x-input[data-size] {
--x-input-height: var(--x-control-height);
--x-input-font-size: var(--x-control-font-size);
}Legacy --x-control-height-md aliases --x-size-height-md. Prefer --x-control-height on sized hosts.
Icon scales
| Token family | Use |
| ----------------- | ----------------------------------------- |
| --x-icon-size-* | Standalone <x-icon> display |
| --x-size-icon-* | Inline control adornments (button, input) |
Scrollbar
Loaded with @xngui/styles. Thin track, rounded thumb; remaps under .dark.
| Token | Role |
| --------------------------- | ---------------------------------- |
| --x-scrollbar-size | WebKit thickness (scrollbar.css) |
| --x-scrollbar-track | Track fill |
| --x-scrollbar-thumb | Thumb fill |
| --x-scrollbar-thumb-hover | Thumb hover fill |
Standalone: @import '@xngui/styles/scrollbar' (needs semantic tokens already loaded).
Color roles
Role scales: primary · secondary · success · warning · danger · info · neutral · accent (50–950).
| Slot | Token | Use |
| -------------- | -------------------------------------------------------- | ---------------------------- |
| bg | --x-{role} | Solid fill |
| foreground | --x-{role}-foreground | On-role text/icon |
| border | --x-{role}-border | Outline border |
| hover / active | --x-{role}-hover / -active | Solid interaction |
| subtle* | --x-{role}-subtle / -subtle-hover / -subtle-active | Soft / ghost / outline fills |
Dark via .dark (toggled by @xngui/theme).
Solid role pairs are checked for WCAG AA by pnpm nx run styles:verify (also runs before styles:build).
Typography
Font sizes (--x-text-*) ship with Tailwind-style paired leadings (--x-text-*-leading).
Whenever you set font-size: var(--x-text-sm), also set line-height: var(--x-text-sm-leading).
Relative multipliers (--x-leading-tight, …) remain for unknown/inherited sizes.
Icon / compact controls may use line-height: 1 (--x-leading-none) for centering.
Focus
Only focus recipe for library controls: add .x-focusable → uses --x-focus-ring-color (← --x-ring), --x-focus-ring-width, --x-focus-ring-offset. Tailwind: ring / outline colors via --color-ring. Do not invent per-component rings.
Structural scales
Spacing, shadow (incl. inset), blur, radius, typography, and motion follow Tailwind v4 default steps (oklch for colors/shadows).
States
Opt-in via attrs/classes (loaded from @xngui/styles). States also set --x-state-* vars so component recipes can compose without specificity fights against :where():
| State | Opt-in | State vars |
| -------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Disabled | [disabled], [aria-disabled="true"], [data-disabled], [data-state="disabled"], .x-disabled | --x-state-opacity (0.5 actions), --x-state-fg-color / --x-state-border-color (0.38 / 0.12 fields), --x-state-cursor, no pointer events |
| Readonly | [readonly], .x-readonly | --x-state-opacity: 1, --x-state-cursor |
| Invalid | [aria-invalid="true"], .x-invalid | --x-state-border-color, --x-state-fg-color, --x-state-focus-ring-color (+ overrides --x-focus-ring-color) |
| Loading | [aria-busy="true"], .x-loading | --x-state-opacity: 1 (spinner / overlay only — no dimming) |
| Focus | .x-focusable + :focus-visible | (outline tokens) |
| Selected | .x-selected only (not global ARIA) | — |
Components must wire those attrs/classes and consume the vars (e.g. border-color: var(--x-state-border-color, var(--x-input-border))). Do not reimplement disabled/invalid/focus looks in component CSS.
Imports
@import '@xngui/styles';
@import '@xngui/styles/scale'; /* optional — already in main entry */
@import '@xngui/styles/base'; /* optional reset */
@import '@xngui/styles/tailwind'; /* optional */
@import '@xngui/icons/fontawesome'; /* optional */Predefined themes
Twenty-nine built-in palettes ship under themes/ — 17 chromatic hues (Tailwind brand spectrum engine) and 12 semantic themes (curated role anchors). See themes/README.md. Import after the foundation layer:
@import '@xngui/styles';
@import '@xngui/styles/themes/blue';
@import '@xngui/styles/themes/github';