spartan/ui
spartan/ui is an Angular UI library. It uses a two-layer architecture:
- Brain (
@spartan-ng/brain) - accessible, unstyled primitives (Angular directives/components),
installed from npm. This is the behavior and accessibility layer.
- Helm (
@spartan-ng/helm) - the styled layer (Tailwind + class-variance-authority). Helm code
is copied into the user's project by the CLI so they own and can customize it.
You compose Helm directives/components onto host elements; Helm wires up the matching Brain
primitive under the hood. Always prefer existing components over hand-written markup.
All CLI commands run through the workspace's runner. Detect it from the project:
- Nx workspace (has
nx.json): npx nx g @spartan-ng/cli:<generator> (or pnpm nx g ...).
- Angular CLI workspace (has
angular.json, no nx.json): ng g @spartan-ng/cli:<generator>.
Current project context
Before generating any code, gather the project context:
npx nx g @spartan-ng/cli:info --json # Nx
ng g @spartan-ng/cli:info --json # Angular CLI
This is read-only and prints JSON with:
workspaceType - nx | angular-cli (decides which runner to use above).
config.componentsPath - where Helm components are copied (e.g. libs/ui).
config.importAlias - the import prefix for Helm, default @spartan-ng/helm.
config.generateAs - library | entrypoint (Nx layout choice).
versions - Angular, Angular CDK, Tailwind, @spartan-ng/brain, @spartan-ng/cli.
iconLibrary - @ng-icons when present.
tailwindCssFile - the global stylesheet that imports the preset.
installedComponents - components already present (do not re-add these).
availableComponents - everything the CLI can generate.
If components.json does not exist, the project is not set up yet - run @spartan-ng/cli:init
first (it installs dependencies and the theme). components.json itself is created when you add the
first component with ui (see cli.md).
Principles
- Use existing components first. Check
installedComponents, then availableComponents. Find
docs via the MCP server (spartan_components_list / spartan_components_get) or the live docs at
https://www.spartan.ng/components/<name>. See mcp.md.
- Compose, do not reinvent. Build dashboards, forms, and dialogs from existing Helm + Brain
pieces rather than custom markup.
- Use built-in variants before custom styles. Buttons, badges, alerts, etc. ship
variant and
size inputs - use them instead of overriding classes.
- Use semantic colors, never raw values.
bg-primary text-primary-foreground, not
bg-blue-500. See rules/styling.md.
Critical rules
Read the rule file before doing the related work:
rules/styling.md - the hlm() util, semantic color tokens, layout-only classes,
gap-* over space-*, size-*, dark mode, no manual z-index on overlays.
rules/forms.md - compose forms with hlmField (label, control, error, description) and
hlmFieldSet / hlmFieldLegend on native <fieldset>/<legend>; option sets (2-7 choices) use
hlm-toggle-group.
rules/composition.md - items belong inside their group; dialogs/sheets need a title;
full Card composition; tabs triggers inside hlm-tabs-list; avatar always has a fallback;
use Alert/Empty/Skeleton/Badge/Separator/Spinner instead of custom markup.
rules/icons.md - icons are <ng-icon name="lucide...">; register with provideIcons;
no manual sizing classes inside components - use the size input.
rules/brain-vs-helm.md - the two-layer model (one headless library, Brain, plus the styled
Helm layer); when to reach for Brain directly vs Helm, and how composition works via directives.
cli.md - every generator (init, ui, ui-theme, healthcheck, info, migrate-*),
with Nx and Angular CLI invocations.
registry.md - the Brain-npm + Helm-copy-in distribution model, components.json, and the
fixed component catalog (the shipped CLI uses no remote or custom registry).
customization.md - theming via the hlm-tailwind-preset.css, CSS variables, the ui-theme
generator, and extending copied Helm components.
mcp.md - using the @spartan-ng/mcp tools, resources, and prompts for discovery.
Key patterns
<!-- Buttons: use variant/size inputs, not custom classes -->
<button hlmBtn variant="destructive" size="lg">Delete</button>
<!-- Icon in a button: ng-icon -->
<button hlmBtn size="icon" variant="ghost">
<ng-icon name="lucideTrash" />
</button>
<!-- Loading state: compose a spinner, there is no isLoading input -->
<button hlmBtn [disabled]="loading()">
@if (loading()) {
<hlm-spinner />
} Save
</button>
<!-- Layout: gap, not space-* ; size-* when width == height -->
<div class="flex items-center gap-2">
<span hlmBadge variant="secondary">beta</span>
</div>
Component selection
| Need |
Component(s) |
| Action / button |
button (hlmBtn), button-group |
| Text/number input |
input, textarea, input-otp, input-group, native-select |
| Choice input |
select, combobox, autocomplete, radio-group, checkbox, switch, slider |
| Toggle 2-7 options |
toggle-group |
| Form layout/validation |
field, label |
| Data display |
table, card, badge, avatar, kbd, item |
| Navigation |
sidebar, navigation-menu, breadcrumb, tabs, pagination |
| Overlays |
dialog, sheet, alert-dialog, popover, hover-card, tooltip |
| Menus |
dropdown-menu, context-menu, menubar, command |
| Feedback |
sonner (toasts), alert, progress, skeleton, spinner |
| Layout/containers |
card, separator, resizable, scroll-area, accordion, collapsible, aspect-ratio |
| Empty states |
empty |
| Dates |
calendar, date-picker |
| Icons |
icon (@ng-icons) |
| Typography |
typography |
Workflow
- Get context. Run
@spartan-ng/cli:info --json. If the project is not set up, run :init,
then add components with :ui (the first :ui run creates components.json).
- Check what is installed. Do not re-add anything in
installedComponents.
- Find the component. Use the MCP tools or
https://www.spartan.ng/components/<name> for the
API and examples (mcp.md). Never guess selectors - confirm them.
- Add it.
npx nx g @spartan-ng/cli:ui --name=<component> (Nx) or
ng g @spartan-ng/cli:ui --name=<component> (Angular CLI). This installs the Brain dependency and
copies the Helm code. Omit --name to get an interactive multiselect.
- Compose correctly. Import the
*Imports const (e.g. HlmDialogImports) or the individual
classes from the import alias, add them to the standalone component's imports, and follow the
composition rules.
- Register icons. Any
<ng-icon> you use must be passed to provideIcons(...) (see
rules/icons.md).
- Verify. After bigger changes or upgrades, run
@spartan-ng/cli:healthcheck to catch
deprecated patterns and fix imports.
- Theme/customize. Edit the copied Helm files and the CSS variables; do not fork Brain.
Quick reference
# Initialize (creates components.json, wires Tailwind + preset)
npx nx g @spartan-ng/cli:init
ng g @spartan-ng/cli:init
# Project context as JSON
npx nx g @spartan-ng/cli:info --json
# Add components (interactive, or pass --name)
npx nx g @spartan-ng/cli:ui
npx nx g @spartan-ng/cli:ui --name=dialog
# Generate theme variables
npx nx g @spartan-ng/cli:ui-theme
# Scan + auto-fix deprecated APIs/imports after an upgrade
npx nx g @spartan-ng/cli:healthcheck --autoFix
Source: spartan-ng/spartan — distributed by TomeVault.
1---2name: spartan-ng-spartan-spartan3description: Spartan Ng Spartan Spartan4---56# spartan/ui78spartan/ui is an Angular UI library. It uses a **two-layer architecture**:910- **Brain (`@spartan-ng/brain`)** - accessible, unstyled primitives (Angular directives/components),11 installed from npm. This is the behavior and accessibility layer.12- **Helm (`@spartan-ng/helm`)** - the styled layer (Tailwind + class-variance-authority). Helm code13 is **copied into the user's project** by the CLI so they own and can customize it.1415You compose Helm directives/components onto host elements; Helm wires up the matching Brain16primitive under the hood. Always prefer existing components over hand-written markup.1718All CLI commands run through the workspace's runner. Detect it from the project:1920- **Nx workspace** (has `nx.json`): `npx nx g @spartan-ng/cli:<generator>` (or `pnpm nx g ...`).21- **Angular CLI workspace** (has `angular.json`, no `nx.json`): `ng g @spartan-ng/cli:<generator>`.2223## Current project context2425Before generating any code, gather the project context:2627```bash28npx nx g @spartan-ng/cli:info --json # Nx29ng g @spartan-ng/cli:info --json # Angular CLI30```3132This is read-only and prints JSON with:3334- `workspaceType` - `nx` | `angular-cli` (decides which runner to use above).35- `config.componentsPath` - where Helm components are copied (e.g. `libs/ui`).36- `config.importAlias` - the import prefix for Helm, default `@spartan-ng/helm`.37- `config.generateAs` - `library` | `entrypoint` (Nx layout choice).38- `versions` - Angular, Angular CDK, Tailwind, `@spartan-ng/brain`, `@spartan-ng/cli`.39- `iconLibrary` - `@ng-icons` when present.40- `tailwindCssFile` - the global stylesheet that imports the preset.41- `installedComponents` - components already present (do not re-add these).42- `availableComponents` - everything the CLI can generate.4344If `components.json` does not exist, the project is not set up yet - run `@spartan-ng/cli:init`45first (it installs dependencies and the theme). `components.json` itself is created when you add the46first component with `ui` (see `cli.md`).4748## Principles49501. **Use existing components first.** Check `installedComponents`, then `availableComponents`. Find51 docs via the MCP server (`spartan_components_list` / `spartan_components_get`) or the live docs at52 `https://www.spartan.ng/components/<name>`. See `mcp.md`.532. **Compose, do not reinvent.** Build dashboards, forms, and dialogs from existing Helm + Brain54 pieces rather than custom markup.553. **Use built-in variants before custom styles.** Buttons, badges, alerts, etc. ship `variant` and56 `size` inputs - use them instead of overriding classes.574. **Use semantic colors, never raw values.** `bg-primary text-primary-foreground`, not58 `bg-blue-500`. See `rules/styling.md`.5960## Critical rules6162Read the rule file before doing the related work:6364- **`rules/styling.md`** - the `hlm()` util, semantic color tokens, layout-only classes,65 `gap-*` over `space-*`, `size-*`, dark mode, no manual z-index on overlays.66- **`rules/forms.md`** - compose forms with `hlmField` (label, control, error, description) and67 `hlmFieldSet` / `hlmFieldLegend` on native `<fieldset>`/`<legend>`; option sets (2-7 choices) use68 `hlm-toggle-group`.69- **`rules/composition.md`** - items belong inside their group; dialogs/sheets need a title;70 full Card composition; tabs triggers inside `hlm-tabs-list`; avatar always has a fallback;71 use `Alert`/`Empty`/`Skeleton`/`Badge`/`Separator`/`Spinner` instead of custom markup.72- **`rules/icons.md`** - icons are `<ng-icon name="lucide...">`; register with `provideIcons`;73 no manual sizing classes inside components - use the `size` input.74- **`rules/brain-vs-helm.md`** - the two-layer model (one headless library, Brain, plus the styled75 Helm layer); when to reach for Brain directly vs Helm, and how composition works via directives.76- **`cli.md`** - every generator (`init`, `ui`, `ui-theme`, `healthcheck`, `info`, `migrate-*`),77 with Nx and Angular CLI invocations.78- **`registry.md`** - the Brain-npm + Helm-copy-in distribution model, `components.json`, and the79 fixed component catalog (the shipped CLI uses no remote or custom registry).80- **`customization.md`** - theming via the `hlm-tailwind-preset.css`, CSS variables, the `ui-theme`81 generator, and extending copied Helm components.82- **`mcp.md`** - using the `@spartan-ng/mcp` tools, resources, and prompts for discovery.8384## Key patterns8586```html87<!-- Buttons: use variant/size inputs, not custom classes -->88<button hlmBtn variant="destructive" size="lg">Delete</button>8990<!-- Icon in a button: ng-icon -->91<button hlmBtn size="icon" variant="ghost">92 <ng-icon name="lucideTrash" />93</button>9495<!-- Loading state: compose a spinner, there is no isLoading input -->96<button hlmBtn [disabled]="loading()">97 @if (loading()) {98 <hlm-spinner />99 } Save100</button>101102<!-- Layout: gap, not space-* ; size-* when width == height -->103<div class="flex items-center gap-2">104 <span hlmBadge variant="secondary">beta</span>105</div>106```107108## Component selection109110| Need | Component(s) |111| ---------------------- | ------------------------------------------------------------------------------------------- |112| Action / button | `button` (`hlmBtn`), `button-group` |113| Text/number input | `input`, `textarea`, `input-otp`, `input-group`, `native-select` |114| Choice input | `select`, `combobox`, `autocomplete`, `radio-group`, `checkbox`, `switch`, `slider` |115| Toggle 2-7 options | `toggle-group` |116| Form layout/validation | `field`, `label` |117| Data display | `table`, `card`, `badge`, `avatar`, `kbd`, `item` |118| Navigation | `sidebar`, `navigation-menu`, `breadcrumb`, `tabs`, `pagination` |119| Overlays | `dialog`, `sheet`, `alert-dialog`, `popover`, `hover-card`, `tooltip` |120| Menus | `dropdown-menu`, `context-menu`, `menubar`, `command` |121| Feedback | `sonner` (toasts), `alert`, `progress`, `skeleton`, `spinner` |122| Layout/containers | `card`, `separator`, `resizable`, `scroll-area`, `accordion`, `collapsible`, `aspect-ratio` |123| Empty states | `empty` |124| Dates | `calendar`, `date-picker` |125| Icons | `icon` (`@ng-icons`) |126| Typography | `typography` |127128## Workflow1291301. **Get context.** Run `@spartan-ng/cli:info --json`. If the project is not set up, run `:init`,131 then add components with `:ui` (the first `:ui` run creates `components.json`).1322. **Check what is installed.** Do not re-add anything in `installedComponents`.1333. **Find the component.** Use the MCP tools or `https://www.spartan.ng/components/<name>` for the134 API and examples (`mcp.md`). Never guess selectors - confirm them.1354. **Add it.** `npx nx g @spartan-ng/cli:ui --name=<component>` (Nx) or136 `ng g @spartan-ng/cli:ui --name=<component>` (Angular CLI). This installs the Brain dependency and137 copies the Helm code. Omit `--name` to get an interactive multiselect.1385. **Compose correctly.** Import the `*Imports` const (e.g. `HlmDialogImports`) or the individual139 classes from the import alias, add them to the standalone component's `imports`, and follow the140 composition rules.1416. **Register icons.** Any `<ng-icon>` you use must be passed to `provideIcons(...)` (see142 `rules/icons.md`).1437. **Verify.** After bigger changes or upgrades, run `@spartan-ng/cli:healthcheck` to catch144 deprecated patterns and fix imports.1458. **Theme/customize.** Edit the copied Helm files and the CSS variables; do not fork Brain.146147## Quick reference148149```bash150# Initialize (creates components.json, wires Tailwind + preset)151npx nx g @spartan-ng/cli:init152ng g @spartan-ng/cli:init153154# Project context as JSON155npx nx g @spartan-ng/cli:info --json156157# Add components (interactive, or pass --name)158npx nx g @spartan-ng/cli:ui159npx nx g @spartan-ng/cli:ui --name=dialog160161# Generate theme variables162npx nx g @spartan-ng/cli:ui-theme163164# Scan + auto-fix deprecated APIs/imports after an upgrade165npx nx g @spartan-ng/cli:healthcheck --autoFix166```167168---169> Source: [spartan-ng/spartan](https://github.com/spartan-ng/spartan) — distributed by [TomeVault](https://tomevault.io).170<!-- tomevault:4.0:skill_md:2026-06-27 -->