Design Tokens
Design tokens are the visual design atoms of the design system — specifically, they are named entities that store visual design attributes.
Overview
Design tokens are the fundamental building blocks of the Catalyst Design System. They define the visual language of the system through reusable, scalable values for colors, typography, spacing, and more.
For existing Catalyst components: keep the pinned CDN stylesheet for legacy variables. Use
@pmi/catalyst-theme for the compatible Tailwind v3 preset and PMI utility configuration.
What are Design Tokens?
Design tokens are platform-agnostic named variables that store visual design attributes. They help maintain consistency across products and platforms by providing a single source of truth for design decisions.
Primitive vs Semantic Tokens
The Catalyst Design System uses a two-tier token architecture to balance flexibility with meaningful abstraction:
Primitive Tokens
Primitive tokens are the foundational, context-independent values in the design system. They represent raw values without any implied usage or meaning.
Characteristics:
- Context-agnostic: Not tied to specific use cases
- Direct values: Represent actual visual properties (hex codes, pixel values, font names)
- Rarely change: Stable foundation that defines the design language
- Named descriptively: Use literal or numeric naming (e.g.,
blue-500,scale-4,font-sans)
Examples:
/* Color primitives */
--color-blue-50: #eff6ff;
--color-blue-500: #3b82f6;
--color-blue-900: #1e3a8a;
/* Spacing primitives */
--scale-1: 0.25rem; /* 4px */
--scale-4: 1rem; /* 16px */
--scale-8: 2rem; /* 32px */
/* Typography primitives */
--font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
--text-sm: 0.875rem; /* 14px */
--font-medium: 500;Semantic Tokens
Semantic tokens reference primitive tokens and add contextual meaning. They communicate intent and purpose, making design decisions self-documenting.
Characteristics:
- Context-aware: Tied to specific use cases or component states
- Reference primitives: Built on top of primitive token values
- Change based on theme: Can be reassigned for different themes (light/dark, brand variations)
- Named by purpose: Use functional naming (e.g.,
color-primary,button-padding,text-md)
Examples:
/* Semantic color tokens */
--color-primary: var(--color-blue-500);
--color-background: var(--color-white);
--color-text: var(--color-gray-900);
--color-border: var(--color-gray-200);
--color-error: var(--color-red-500);
--color-success: var(--color-green-500);
/* Semantic spacing tokens */
--button-padding-x: var(--scale-4);
--button-padding-y: var(--scale-2);
--card-gap: var(--scale-6);
/* Semantic typography tokens */
--text-body-md: var(--);Comparison Table
| Aspect | Primitive Tokens | Semantic Tokens |
|---|---|---|
| Purpose | Define the raw design palette | Communicate usage and intent |
| Naming | Descriptive/literal (blue-500) | Functional/contextual (color-primary) |
| Flexibility | Fixed values, rarely change | Can be remapped for themes |
| References | Direct values (hex, px, names) | Reference primitive tokens |
| Examples | --color-blue-500, --scale-4 | --color-primary, --button-padding |
| Use Cases | Building semantic tokens | Direct application in components |
| Theming | Theme-independent | Theme-dependent |
When to Use Each
Use Primitive Tokens when:
- Defining the core design palette
- You need exact, specific values
- Building the foundation of semantic tokens
- Creating design system documentation
Use Semantic Tokens when:
- Building components and interfaces
- You need contextual meaning
- Supporting multiple themes (light/dark mode)
- Communicating design intent to developers
Token Categories
The Catalyst Design System organizes tokens into several categories:
Colors
Color tokens define the color palette used throughout the system, including brand colors, semantic colors (success, error, warning), and neutral scales.
Typography
Typography tokens define font families, sizes, weights, line heights, and letter spacing values.
Spacing
Spacing tokens define consistent spacing values for layouts, padding, margins, and gaps using a harmonious scale.
Border Radius
Border radius tokens define consistent corner rounding values for creating visual hierarchy and consistency.
CSS Variable Naming Convention
Catalyst uses a specific naming convention for CSS custom properties (CSS variables) that reflects the design system's architecture and usage patterns.
Naming Pattern
The Catalyst Design System follows these naming patterns:
--{scale} # For spacing values
--{category}-{property} # For semantic tokens
--colors-{color}-{shade} # For color primitivesCore Token Prefixes
1. Scale Tokens (--scale-*)
Spacing values use a consistent scale-based naming convention:
/* Spacing scale tokens */
--scale-4: 0.25rem; /* 4px */
--scale-8: 0.5rem; /* 8px */
--scale-12: 0.75rem; /* 12px */
--scale-16: 1rem; /* 16px */
--scale-20: 1.25rem; /* 20px */
--scale-24: 1.5rem; /* 24px */
--scale-32: 2rem; /* 32px */
--scale-36: 2.25rem; /* 36px */
--scale-40: 2.5rem; /* 40px */
--scale-72: 4.5rem; /* 72px */Usage in components:
<div className="gap-y-[--scale-32] md:gap-y-[--scale-40]">
<div className="space-y-[--scale-16]">
<ul className="space-y-[--scale-12] ps-[--scale-20]">
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
</div>2. Color Tokens (--colors-*)
Color primitives follow the Tailwind naming pattern with PMI brand colors:
/* PMI brand color primitives */
--colors-violet-50: #efedf3;
--colors-violet-500: #4f17a8;
--colors-violet-900: #1a0837;
--colors-aqua-50: #eefafa;
--colors-aqua-500: #00799e;
--colors-aqua-900: #03202f;
--colors-off-black-50: #dad6e1;
--colors-off-black-800: #200f3b;
--colors-off-black-900: #170a2a;
/* Neutral scale */
--colors-neutral-50: #f7f4ef;
--colors-neutral-500: #666666;
--colors-neutral-900: #232323;Tailwind usage:
// Access via Tailwind utility classes
<button className="bg-pmi-violet-500 text-white">
Primary Button
</button>
<div className="text-pmi-off-black-800 dark:text-pmi-off-black-200">
Content
</div>3. Semantic Text Tokens (--text-*)
Semantic tokens for text colors in light/dark themes:
/* Semantic text colors */
--text-primary: /* Theme-aware text color */ --text-secondary: /* Secondary text color */;Usage:
<div className="text-[--text-primary]">Primary text content</div>4. Semantic Surface Tokens (--surface-*)
Background and surface color tokens:
/* Surface tokens */
--surface-primary: /* Primary background */ --surface-secondary: /* Secondary background */;Usage:
<div className="bg-[--surface-page-background]">
<div className="bg-gradient-to-b from-[--surface-secondary] to-[--surface-primary]">Content</div>
</div>5. Semantic Fill Tokens (--fill-*)
Colored fill states for components:
/* Fill tokens for component states */
--fill-info-softer: /* Info color softer variant */ --fill-accent-softer: /* Accent color softer variant */
--fill-warning-soft: /* Warning color soft variant */ --fill-off-black-dark: /* Dark off-black fill */;Usage:
<button className="hover:bg-[--fill-info-softer]">
Info Button
</button>
<button className="hover:bg-[--fill-accent-softer]">
Accent Button
</button>6. Component-Specific Tokens
Custom tokens for specific component needs:
/* Carousel-specific tokens */
--carousel-content-max-width: 1128px;
--carousel-controls-width: calc(100% - var(--scale-72));
--carousel-content-padding-left: max(
var(--scale-36),
calc((100% - var(--carousel-content-max-width) + var(--scale-16)) / 2)
);Naming Best Practices
- Use kebab-case: All lowercase with hyphens
- Numeric scale values: Use actual pixel values (4, 8, 12, 16, etc.) not abstract numbers
- Prefix consistently:
--scale-*for spacing--colors-*for color primitives--text-*for text colors and sizes--surface-*for backgrounds--fill-*for component fills
- Be descriptive:
--scale-32is clearer than--spacing-8
Tailwind Configuration
Tokens are defined in the Tailwind theme and accessed via utility classes:
// Using semantic tokens via Tailwind classes
<button className="bg-primary text-white px-4 py-2 rounded-button">
Click me
</button>
// Equivalent to:
<button className="bg-blue-500 text-white px-4 py-2 rounded-md">
Click me
</button>Token distribution
@pmi/catalyst-theme (Tailwind compatibility)
Theme V3 keeps the Tailwind utilities and variable mappings required by existing Catalyst packages. It mirrors the established contract while the next semantic-token system develops separately:
- Semantic CSS variables (
--surface-*,--text-*,--fill-*,--border-*, …) - Legacy
--scale-*spacing aliases - Theme scope classes (
.theme-pmi-light,.theme-pmi-dark) - PMI color primitives as Tailwind utilities (
bg-pmi-violet-500, etc.)
Do not treat the preset as authorization to remove the CDN when an application depends on legacy variables.
Tailwind v4 type adapter
@pmi/catalyst-theme intentionally publishes a Tailwind v3 Config because v3 remains the supported
downstream contract. Tailwind v4 uses a different UserConfig type even though its legacy @config bridge
can consume the preset at runtime. A v4 application should isolate that type mismatch in its Tailwind config:
import type { Config } from 'tailwindcss';
import { tailwindThemePreset } from '@pmi/catalyst-theme';
// Type-only compatibility boundary between the v3 preset and a v4 application.
const catalystThemePreset = tailwindThemePreset as unknown as Config;
export default {
presets: [catalystThemePreset],
} satisfies Config;Load the adapter through Tailwind v4's @config directive and include application and Catalyst package output
in source detection:
@import 'tailwindcss';
@config './tailwind.config.ts';
@source './src/**/*.{js,ts,jsx,tsx,mdx}';
@source './node_modules/@pmi/catalyst-*/dist/**/*.{js,mjs}';Keep this cast at the application boundary. Do not widen the Theme package's published type or spread the cast through component code.
CDN stylesheet (recommended for legacy variables)
The Catalyst Design System distributes its established CSS custom-property contract through a pinned CDN stylesheet. Keep it in applications that consume legacy variables.
CDN URL structure
The PMI Design System CDN follows this URL pattern:
https://cdn.pmi.org/dsm/styles/v1/{timestamp}-{hash}.min.cssExample:
<link
rel="stylesheet"
href="https://cdn.pmi.org/dsm/styles/v1/20241010-145120-162392c2-a329-424f-b34a-c2c9fc802e43.min.css"
/>What's included
The CDN-distributed CSS file contains:
-
CSS Custom Properties (Variables):
- Color tokens (
--colors-*) - Spacing scale (
--scale-*) - Typography tokens (
--text-*,--font-*) - Semantic tokens (
--surface-*,--fill-*,--border-*)
- Color tokens (
-
Theme Definitions:
- Light theme (
.theme-pmi-light) - Dark theme (
.theme-pmi-dark)
- Light theme (
-
Component-Specific Tokens:
- Custom properties for complex components
- Carousel, navigation, and layout tokens
Font loading from CDN
The CDN also hosts the Aeonik font family used throughout the design system. Fonts are separate from the token stylesheet—continue loading them alongside the legacy variable stylesheet:
<head>
<!-- Preload critical font weights -->
<link
rel="preload"
href="https://cdn.pmi.org/dsm/fonts/Aeonik/Aeonik-Regular.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
/>
<link
rel="preload"
href="https://cdn.pmi.org/dsm/fonts/Aeonik/Aeonik-Medium.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
/>
</head>Using semantic tokens
Once the CDN stylesheet is loaded, its legacy tokens are consumed as CSS custom properties:
/* Direct CSS usage */
.my-component {
background: var(--surface-primary);
color: var(--text-primary);
padding: var(--scale-16);
border-radius: var(--scale-8);
}
/* Hover states */
.my-button:hover {
background: var(--fill-info-softer);
}With Tailwind class names:
Background colors from the theme preset are available as primitive utilities:
<div className="bg-pmi-neutral-100">Content using semantic and primitive tokens</div>With Tailwind arbitrary values:
<div className="bg-[--surface-primary] p-[--scale-16] text-[--text-primary]">
Content using semantic tokens
</div>Theme switching
Switch themes by applying a scope class on an ancestor. With the preset or CDN, use .theme-pmi-light and .theme-pmi-dark:
// Light theme
<html className="theme-pmi-light">
// Dark theme
<html className="theme-pmi-dark">For localized overrides without changing the page root, nest the opposite theme scope on a descendant.
Legacy CDN consumers should use the production CDN for production applications and the integration CDN for testing/staging environments.
Best practices
- Keep the CDN for legacy variables: Use the pinned Catalyst 2.0 PMI DSM stylesheet when existing variables are required
- Use the preset for current Tailwind utilities: Do not treat it as authorization to remove the CDN dependency
- Monitor updates: Subscribe to design system release notes
- Test before deploying: Verify new token versions in non-production environments
- Use preloading: Improve perceived performance with resource hints for fonts
- Document your version: Keep track of which CDN version your app uses during migration
Typography
Installation and usage of PMI's brand typeface Aeonik using either Tailwind CSS or direct imports from CDN.
Country Flag Icons
Recommended approach for rendering country flag icons using the country-flag-icons package. Provides comprehensive ISO 3166-1 coverage with built-in React components, tree-shakeable imports, and zero maintenance overhead.