# Hallmark's Token System for CSS Custom Properties: Architecture and Implementation

> Explore Hallmark's token system for CSS custom properties. Discover its layered architecture using data-theme attributes for theme overrides and a clear value proposition.

- Repository: [Hassan El Mghari/hallmark](https://github.com/Nutlope/hallmark)
- Tags: architecture
- Published: 2026-08-02

---

**Hallmark drives its entire visual design through a layered CSS custom property architecture defined in [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css), using `:root` defaults for base tokens and `[data-theme]` attribute selectors to override colors, typography, and component shapes per theme.**

The open-source Hallmark project (Nutlope/hallmark) implements a robust **token system for CSS custom properties** that enables instant theme switching without JavaScript frameworks. By centralizing all design decisions—from OKLCH color palettes to border radii—into cascading variables, the system allows any component to inherit theme-specific values automatically through standard CSS cascade inheritance.

## Root Defaults: The Foundation Layer

The token system establishes comprehensive defaults within the `:root` selector in [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css) (lines 14-100). This foundation provides the design language applied when no specific theme is active, defining every visual aspect through semantic naming conventions.

### Color Palette Using OKLCH

Colors use the **OKLCH** color space for perceptual uniformity, ensuring consistent luminance across different hues. The naming follows functional roles rather than literal values:

- `--color-paper`: Background surfaces
- `--color-ink`: Primary text and icons
- `--color-accent`: Interactive elements and highlights
- `--color-rule`: Borders and dividers

### Typography Scale and Font Stacks

Typography separates concerns across three font categories:

- `--font-display`: Headlines and prominent text
- `--font-body`: Paragraphs and long-form content
- `--font-label`: UI elements and captions

The type scale spans `--text-xs` through `--text-2xl`, with a dedicated `--text-display` variable for hero headings. Supporting tokens like `--tracking-display` and `--lh-*` (line-height) fine-tune readability.

### Layout, Spacing, and Animation

**Layout tokens** constrain visual density:

- `--space-xs` through `--space-xl`: Incremental spacing utilities
- `--page-max`: Maximum content width constraints
- `--measure`: Optimal line length for readability
- `--section-gap`: Vertical rhythm between major sections

**Interaction tokens** control motion:

- `--dur-fast`, `--dur-base`, `--dur-slow`: Animation durations
- `--ease-*`: Cubic-bezier curves for state transitions

### UI Component Primitives

UI-specific tokens ensure consistent component styling:

- `--radius-card`, `--radius-pill`, `--radius-input`: Border radii for specific elements
- `--rule-card`: Border thickness
- `--shadow-card`: Elevation shadows
- `--z-*`: Z-index stacking contexts

## Per-Theme Token Overrides

Individual themes override specific `:root` values using attribute selectors `[data-theme="theme-name"]` defined sequentially in [`tokens.css`](https://github.com/Nutlope/hallmark/blob/main/tokens.css). Each block selectively redefines only the tokens necessary to achieve its visual identity, leaving unrelated properties unchanged to maintain design system integrity.

### Color and Typography Remapping

The **midnight** theme demonstrates the override pattern (lines 20-46):

```css
[data-theme="midnight"] {
  --color-paper:    oklch(15% 0.022 250);
  --color-ink:      oklch(90% 0.02 270);
  --font-display:   "Geist", "Futura", "Avenir Next", ui-sans-serif, sans-serif;
  --text-display:   clamp(2.75rem, 5.0vw + 1.0rem, 5.25rem);
  --tracking-display: -0.02em;
}

```

Themes may swap font families entirely—transitioning from serif editorial styles to monospaced technical aesthetics—or adjust typographic scales to accommodate different character widths and densities.

### Layout Density Adjustments

Spacing and layout variables like `--section-gap` and `--page-max` are occasionally modified per theme to reflect different design philosophies, from airy editorial layouts to compact utility interfaces, without affecting component markup.

## Component-Shape Token Overrides

Following the theme color and typography blocks, a secondary override layer adjusts **shape tokens** (`--radius-*`, `--rule-card`, `--shadow-card`) to control the physical appearance of cards, inputs, and buttons. This separation allows themes to maintain consistent colors while varying their "voice" through geometric styling.

The **garden** theme applies friendly, rounded aesthetics (lines 447-449):

```css
[data-theme="garden"] {
  --radius-card: 10px;
  --radius-pill: 8px;
  --radius-input: 8px;
}

```

These overrides ensure that UI primitives inherit the intended visual character without requiring component-specific CSS modifications.

## Implementing Themes in Practice

### Activating Themes in HTML

Apply a theme by setting the `data-theme` attribute on the `<html>` element or any ancestor container:

```html
<!DOCTYPE html>
<html data-theme="midnight" lang="en">
  <head>
    <link rel="stylesheet" href="css/tokens.css">
  </head>
  <body>
    <!-- Content inherits midnight tokens automatically -->
  </body>
</html>

```

### Consuming Tokens in Component CSS

Components reference tokens using standard `var()` syntax, ensuring automatic theme inheritance regardless of which theme is active:

```css
.card {
  background-color: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-body);
  border-radius: var(--radius-card);
  border: var(--rule-card) solid var(--color-rule);
  box-shadow: var(--shadow-card);
  padding: var(--space-md);
}

.pill {
  font-family: var(--font-label);
  border-radius: var(--radius-pill);
}

```

### Programmatic Theme Switching

JavaScript can toggle themes instantly without page reloads by modifying the dataset on `document.documentElement`:

```javascript
function setTheme(themeName) {
  document.documentElement.dataset.theme = themeName;
}

// Switch to garden theme - colors, fonts, and radii update immediately
setTheme('garden');

```

This update propagates instantly because all visual properties reference CSS custom properties rather than hardcoded values, enabling zero-cost runtime theme changes.

### Key Source Files

- **[`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css)**: Core token definitions, root defaults, and per-theme overrides (see lines 14-100 for defaults, lines 20+ for theme blocks)
- **[`site/index.html`](https://github.com/Nutlope/hallmark/blob/main/site/index.html)**: Example page demonstrating theme activation via `data-theme` attributes
- **[`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js)**: JavaScript utilities for theme toggling and persistence
- **[`site/_tests/07-foundry-compliance/style.css`](https://github.com/Nutlope/hallmark/blob/main/site/_tests/07-foundry-compliance/style.css)**: Test suites verifying token usage across different theme configurations

## Summary

- Hallmark's architecture uses **CSS custom properties** defined in [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css) to create a maintainable, themeable design system with single-source truth.
- **Root defaults** in `:root` establish base values for OKLCH colors, typography stacks, spacing scales, and UI metrics that apply globally.
- **Per-theme overrides** leverage `[data-theme]` selectors to remap specific tokens like `--color-paper` and `--font-display` without duplicating component code.
- **Component-shape tokens** (`--radius-card`, `--shadow-card`) are overridden separately per theme to control physical appearance independently of color.
- Themes activate via HTML `data-theme` attributes and propagate instantly through `var()` references, enabling runtime switching with zero repaint costs.

## Frequently Asked Questions

### How do I add a new theme to Hallmark's token system?

Add a `[data-theme="your-name"]` selector block to [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css) following the existing theme definitions. Copy an existing theme's structure and redefine only the tokens requiring changes—such as `--color-paper`, `--font-display`, or `--radius-card`. The cascade automatically applies your overrides while inheriting undefined tokens from the `:root` defaults, ensuring consistency with the base system.

### Why does Hallmark use OKLCH for color tokens instead of HEX or RGB?

The system uses **OKLCH** (Oklab Lightness, Chroma, Hue) because it provides perceptual uniformity, meaning color changes appear consistent to human vision regardless of hue. This prevents the luminance shifts common in HSL and ensures that `--color-ink` maintains readable contrast against `--color-paper` across different theme palettes, particularly important for accessibility in dark themes like **midnight**.

### Can I use Hallmark's CSS custom properties in a React or Vue application?

Yes. Since the tokens are standard CSS custom properties, they function in any framework outputting HTML and CSS. Import [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css) into your global stylesheets, then reference variables like `var(--color-accent)` in your component styles. For dynamic theme switching, update `document.documentElement.dataset.theme` via framework state management or the vanilla JavaScript `setTheme()` pattern demonstrated in [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js).

### What happens if a token is missing in a theme definition?

If a theme override omits a specific token, the browser falls back to the `:root` default defined in the first block of [`tokens.css`](https://github.com/Nutlope/hallmark/blob/main/tokens.css). This **selective override** approach means themes only declare values that differ from the base system, reducing CSS repetition and ensuring visual consistency for unspecified properties across all themes.