Connect Figma Tokens to PrimeNG in Angular 20+: Storybook + Chromatic Guardrails (Nx, Signals, A11y)

Connect Figma Tokens to PrimeNG in Angular 20+: Storybook + Chromatic Guardrails (Nx, Signals, A11y)

Design tokens that compile from Figma to CSS variables, wire into PrimeNG and charts, previewed in Storybook, and locked by Chromatic—polish with metrics.

If a token change can’t pass through Storybook + Chromatic, it doesn’t belong in production.
Back to all posts

I’ve watched token drift sink enterprise UI polish. The fix is a pipeline: Figma tokens compile to CSS variables, PrimeNG reads them, Storybook previews them, and Chromatic guards them. In this playbook I’ll show the exact Nx + Angular 20+ setup I use on dashboards, kiosks, and multi‑tenant apps.

Hook: Figma → PrimeNG with Guardrails (Storybook + Chromatic)

The scene

Quarter‑close at a telecom client: charts didn’t match the brand refresh, density toggles were inconsistent, and a bug turned DataTable focus outlines invisible. We wired Figma tokens into our Angular 20 + PrimeNG stack, previewed everything in Storybook, and let Chromatic block regressions. The next brand change shipped in under an hour.

If you need to hire an Angular developer or Angular consultant for a similar integration, this is the exact, repeatable approach I use across Fortune 100 dashboards and kiosk software.

Why Figma Tokens in Angular 20 + PrimeNG Matter

Outcomes you can measure

As teams plan 2025 Angular roadmaps, token pipelines turn subjective polish into a measurable engineering practice. UX polish coexists with performance budgets, and design consistency scales across role‑based, multi‑tenant apps.

  • Fewer theme bugs: 60–80% drop in visual defects after Chromatic adoption (my averages on media/insurance dashboards)

  • Faster brand refresh: minutes, not sprints—tokens propagate to PrimeNG and charts instantly

  • Accessible by default: AA contrast enforced via Storybook a11y and token constraints

  • Performance preserved: CSS variables don’t inflate bundles; Lighthouse Mobile stays high

Architecture: Nx Libs, Signals/SignalStore, and CSS Variables

// libs/design-tokens/src/tokens.json
{
  "color": {
    "primary": { "500": { "value": "#4C7AF2" } },
    "accent":  { "500": { "value": "#00C2A8" } },
    "danger":  { "500": { "value": "#E65050" } },
    "surface": { "0":   { "value": "#0B0E14" }, "100": { "value": "#111827" }, "900": { "value": "#FFFFFF" } }
  },
  "typography": {
    "fontFamily": { "value": "'Inter', system-ui, -apple-system, Segoe UI, Roboto" },
    "size": { "base": { "value": 16 }, "scale": { "value": 1.125 } }
  },
  "density": { "cozy": { "value": 8 }, "compact": { "value": 4 } }
}
/* libs/design-tokens/dist/tokens.css */
:root { /* AngularUX palette */
  --ux-color-primary-500: #4C7AF2;
  --ux-color-accent-500:  #00C2A8;
  --ux-color-danger-500:  #E65050;
  --ux-surface-0:         #0B0E14;
  --ux-surface-100:       #111827;
  --ux-surface-900:       #FFFFFF;
  --ux-font-family:       'Inter', system-ui, -apple-system, Segoe UI, Roboto;
  --ux-font-size-base:    16px;
  --ux-font-scale:        1.125;
  --ux-density-cozy:      8px;
  --ux-density-compact:   4px;
}
// libs/ui-theme/src/lib/theme.store.ts
import { signal, computed, effect, Injector } from '@angular/core';
import { signalStore, withState } from '@ngrx/signals';

interface ThemeState {
  mode: 'light' | 'dark';
  density: 'cozy' | 'compact';
  scale: 1 | 1.125 | 1.25;
}

export const ThemeStore = (injector: Injector) => signalStore(
  withState<ThemeState>({ mode: 'light', density: 'cozy', scale: 1 }),
)((store) => {
  const cssVars = computed(() => ({
    '--ux-density': store.density() === 'cozy' ? 'var(--ux-density-cozy)' : 'var(--ux-density-compact)',
    '--ux-font-size-base': `calc(var(--ux-font-size-base) * ${store.scale()})`,
    '--p-primary-500': 'var(--ux-color-primary-500)', // PrimeNG variables
    '--p-green-500':   'var(--ux-color-accent-500)',
    '--p-red-500':     'var(--ux-color-danger-500)'
  }));

  effect(() => {
    const el = document.documentElement;
    const vars = cssVars();
    for (const [k, v] of Object.entries(vars)) el.style.setProperty(k, v);
    el.classList.toggle('theme-dark', store.mode() === 'dark');
  });

  return {
    mode: store.mode,
    density: store.density,
    scale: store.scale,
    setMode: (m: ThemeState['mode']) => store.mode.set(m),
    setDensity: (d: ThemeState['density']) => store.density.set(d),
    setScale: (s: ThemeState['scale']) => store.scale.set(s)
  };
});

Workspace layout

Keep tokens in an Nx lib so they version with code and drive Storybook + Chromatic previews in isolation.

  • libs/design-tokens: Figma JSON + build to CSS variables

  • libs/ui-theme: ThemeStore (Signals/SignalStore) + helpers

  • libs/ui-components: PrimeNG wrappers + Storybook stories

  • apps/web: Angular 20+ app consuming tokens

Figma → CSS variables

Export with Tokens Studio (Figma) to JSON. Transform with Style Dictionary (or a tiny Node script) to :root CSS variables so PrimeNG and charts share the same source.

State via Signals/SignalStore

Signals make runtime theme flips instant without change detection storms. SignalStore adds dev ergonomics and testability.

  • Theme (light/dark), density (cozy/compact), typography scale

  • Persisted per tenant/role via Firebase Remote Config or localStorage

Map Tokens to PrimeNG and Your Components

/* apps/web/src/styles/_primeng-overrides.scss */
:root {
  --p-focus-ring: 0 0 0 3px color-mix(in srgb, var(--ux-color-primary-500) 40%, transparent);
  --p-content-padding: var(--ux-density);
}

.p-inputtext, .p-button { font-family: var(--ux-font-family); }
.p-datatable .p-datatable-tbody > tr > td { padding: var(--ux-density); }

.theme-dark {
  --p-text-color: var(--ux-surface-900);
  --p-surface-0:  var(--ux-surface-100);
}

PrimeNG variables

PrimeNG reads CSS variables, so your tokens apply to DataTable, Input, Menus without rewriting component SCSS.

  • Use the new PrimeNG CSS variable themes (e.g., Lara/Saga) as a base

  • Override with your token variables at :root or .theme-* scopes

Density + focus states

In kiosk flows for a major airline, tokenized focus rings and compact density saved seconds per passenger, even offline.

  • Token‑driven padding/row heights

  • AA‑visible focus outlines and state colors

Storybook Integration: A11y, Typography, and Density Controls

// .storybook/preview.ts
import type { Preview } from '@storybook/angular';

const preview: Preview = {
  globalTypes: {
    themeMode: { defaultValue: 'light' },
    density: { defaultValue: 'cozy' },
    scale: { defaultValue: 1 }
  },
  decorators: [
    (story, context) => {
      const root = document.documentElement;
      root.classList.toggle('theme-dark', context.globals.themeMode === 'dark');
      root.style.setProperty('--ux-density', `var(--ux-density-${context.globals.density})`);
      root.style.setProperty('--ux-font-size-base', `calc(16px * ${context.globals.scale})`);
      return story();
    }
  ],
  parameters: {
    a11y: { element: '#root', manual: false }
  }
};
export default preview;

Toolbar for live tokens

Design and engineering preview the same tokens. Screenshots and specs live with components, not in PDFs.

  • Theme (light/dark), density, font scale

  • Docs that show token values next to components

A11y and contrast

We caught invisible link text in an insurance telematics dashboard before it hit staging—because contrast was a Storybook rule, not a suggestion.

  • @storybook/addon-a11y with WCAG AA rules

  • Chromatic links a11y results to visual diffs

Chromatic Visual Regression + CI Budgets

# .github/workflows/ci.yml
name: ci
on: [pull_request]
jobs:
  test_build_storybook:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci
      - run: npx nx run-many -t test build-storybook --parallel
      - name: Chromatic
        uses: chromaui/action@v1
        with:
          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
          exitOnceUploaded: true
          autoAcceptChanges: false
          onlyChanged: true
      - name: Lighthouse CI
        run: |
          npx lhci autorun --config=./lighthouse/lighthouserc.json
// angular.json (snippet)
"budgets": [{
  "type": "initial",
  "maximumWarning": "500kb",
  "maximumError": "700kb"
}]

Why Chromatic

Chromatic has saved my teams from hard‑to‑spot regressions in PrimeNG tables, calendars, and stepper flows countless times.

  • Token diffs show up as visual changes on stories

  • Approvals become a design+eng gate, not a Slack thread

Wire into CI

  • Per‑PR Chromatic runs with thresholds

  • Fail fast on bundle budgets and a11y errors

Budgets and metrics

UX polish should not cost you performance. Prove it every PR.

  • Lighthouse CI for INP/LCP smoke checks

  • Angular budgets to catch accidental bloat

Charts (D3/Highcharts/Three.js) on the Same Tokens

// libs/ui-components/src/lib/highcharts-theme.ts
import Highcharts from 'highcharts';

export function applyHighchartsTheme() {
  const primary = getComputedStyle(document.documentElement)
    .getPropertyValue('--ux-color-primary-500').trim();
  const accent = getComputedStyle(document.documentElement)
    .getPropertyValue('--ux-color-accent-500').trim();

  Highcharts.setOptions({
    colors: [primary, accent, '#a3a3a3'],
    chart: { backgroundColor: 'transparent' },
    title: { style: { color: primary, fontFamily: 'var(--ux-font-family)' } },
    tooltip: { backgroundColor: 'var(--p-surface-0)', borderColor: primary }
  });
}

Why it matters for dashboards

On a telecom advertising analytics platform, we used tokens to unify colors across Highcharts, PrimeNG tables, and D3 mini‑sparklines—one change, everywhere.

  • Role‑based palettes (finance vs. ops) without JS rewrites

  • Data virtualization + Canvas/Three.js respects density tokens

Accessibility, Typography, and Density: UX Details that Scale

Typography scale

  • Modular scale via tokens ensures consistent rhythm

  • Storybook controls show 1x/1.125x/1.25x live

Contrast and focus

I’ve shipped kiosk flows on airport hardware with card readers and scanners; tokenized focus states and larger tap targets reduced mis‑taps and sped up boarding.

  • WCAG AA as a build check, not a guideline

  • PrimeNG focus rings and hover states tokenized

Density controls

In employee tracking systems and VPS schedulers, compact density increased visible rows by ~25% while staying AA accessible.

  • Compact mode for analysts, cozy for managers

  • Virtualized tables use tokenized rowHeight

Example: Wiring a PrimeNG DataTable Story with Tokens

// libs/ui-components/src/lib/data-table/data-table.stories.ts
import { Meta, StoryObj } from '@storybook/angular';
import { TableModule } from 'primeng/table';
import { CommonModule } from '@angular/common';

const meta: Meta = {
  title: 'Data/PrimeNG DataTable',
  component: undefined as any,
  decorators: [
    moduleMetadata({ imports: [CommonModule, TableModule] })
  ],
  argTypes: { density: { control: 'radio', options: ['cozy', 'compact'] } }
};
export default meta;

type Story = StoryObj;
export const Basic: Story = {
  args: { density: 'cozy' },
  render: (args) => ({
    template: `
      <p-table [value]="rows" [style.padding]="densityPadding">
        <ng-template pTemplate="header">
          <tr><th>Employee</th><th>Status</th></tr>
        </ng-template>
        <ng-template pTemplate="body" let-r>
          <tr><td>{{r.name}}</td><td>{{r.status}}</td></tr>
        </ng-template>
      </p-table>
    `,
    props: {
      rows: [{ name: 'A. Lee', status: 'Active' }],
      densityPadding: `var(--ux-density-${args['density']})`
    }
  })
};

Story and controls

This is the pattern I drop into role‑based dashboards: density and theme toggleable per story, so product can sign off without staging wars.

Performance Guardrails and Operationalizing

Keep it fast

  • CSS variables are static and tiny to ship

  • No dynamic SCSS at runtime; avoid style recalcs

Measure

On IntegrityLens (AI‑powered verification system), we measured INP while streaming and toggling density—Signals kept reflows limited and deterministic.

  • Angular DevTools render counts for token toggles

  • Lighthouse Mobile targets (e.g., 90+ LCP/INP)

Rollout

I’ve done this for multi‑tenant insurance telematics portals and device management dashboards—zero forks, zero copy/paste.

  • Feature‑flag theme variants (Firebase Remote Config)

  • Tenant‑specific palettes without forks

When to Hire an Angular Developer for Legacy Rescue

Good fits

If your codebase is chaotic, I can help stabilize. See my work at the NG Wave component library and the code rescue playbook at gitPlumbers—both are live and battle‑tested.

  • AngularJS → Angular migrations that need a design system

  • PrimeNG apps with inconsistent themes and accessibility gaps

  • Teams wanting Chromatic + Storybook discipline and CI budgets

How an Angular Consultant Approaches Signals Migration

Pragmatic adoption

Signals + SignalStore are a low‑risk entry point: UX teams see immediate value, and engineering builds confidence with metrics.

  • Start with theme/density store for quick UX wins

  • Measure render counts before/after with DevTools

Final Takeaways and Next Steps

Recap

If you need a remote Angular expert for hire to wire this up, I can join as a contractor or consultant and leave you with a durable, documented pipeline.

  • Figma tokens → CSS variables in an Nx lib

  • Signals/SignalStore ThemeStore applies vars at runtime

  • PrimeNG + charts consume the same tokens

  • Storybook previews; Chromatic guards; CI budgets enforce performance

Related Resources

Key takeaways

  • Ship Figma tokens as CSS variables, not hardcoded SCSS—PrimeNG and charts read from the same source.
  • Use an Nx tokens lib, a Signals/SignalStore ThemeStore, and a Storybook toolbar for theme/density/a11y previews.
  • Chromatic blocks token drift: visual diffs, contrast checks, and per‑PR approvals.
  • Typography, density, and color tokens drive PrimeNG, Highcharts/D3, and data tables consistently.
  • Performance budgets and Lighthouse/INP are protected: tokens don’t bloat bundles when compiled as CSS vars.
  • Multi‑tenant/role‑based themes are Feature‑Flaggable (Firebase Remote Config) without code rewrites.

Implementation checklist

  • Export tokens from Figma (Tokens Studio) to JSON in an Nx lib
  • Transform tokens → CSS variables via Style Dictionary or custom builder
  • Map tokens to PrimeNG variables and component CSS parts
  • Build a ThemeStore (Signals/SignalStore) for theme + density + contrast modes
  • Wire Storybook toolbar toggles; add a11y + interactions addons
  • Enable Chromatic visual tests and thresholds; require approvals on diffs
  • Connect chart libraries (Highcharts/D3) to the same tokens
  • Add performance budgets and Lighthouse/INP checks in CI

Questions we hear from teams

How much does it cost to hire an Angular developer for a tokens + Storybook + Chromatic setup?
Typical engagements start at 2–4 weeks. Small teams land it in 40–80 hours; complex, multi‑tenant platforms run 3–6 weeks. Fixed‑fee pilots available after a short code assessment.
What does an Angular consultant do in this workflow?
I set up Nx libs, token builds, ThemeStore with Signals, PrimeNG overrides, Storybook a11y + Chromatic, and CI budgets. I also train your team to own the pipeline and measure results.
How long does an Angular upgrade or Signals adoption take?
Signals adoption for theming/density is 1–2 sprints. Full upgrades (e.g., Angular 15→20) run 4–8 weeks alongside delivery, using feature flags and CI guardrails to avoid freezes.
Can we use these tokens for charts and role-based dashboards?
Yes. Highcharts/D3/Canvas read the same CSS variables. Role‑based palettes and density settings can be feature‑flagged per tenant without forking code.
Will Chromatic slow us down?
No. It speeds review by making token diffs visual and reviewable. Approvals take minutes, and you stop shipping accidental regressions that cost days later.

Ready to level up your Angular experience?

Let AngularUX review your Signals roadmap, design system, or SSR deployment plan.

Hire Matthew — Remote Angular Expert, Available Now See Live Components at NG Wave (Signals + Three.js)

NG Wave

Angular Component Library

A comprehensive collection of 110+ animated, interactive, and customizable Angular components. Converted from React Bits with full feature parity, built with Angular Signals, GSAP animations, and Three.js for stunning visual effects.

Explore Components
NG Wave Component Library

Related resources