Skip to main content
Styles

Color

Draft

A two-tier system of primitive palettes and semantic tokens that keeps every surface, text, and border themeable without touching component code.

Common alternative names

Color palette, colour, theme colors, color tokens


Principles

Semantic over literal

Every color in the system has a role, not just a value. Instead of reaching for "blue-600", you use --color-action-primary — and the system handles what that means in light mode, dark mode, or any future theme. This keeps intent readable and theme switching painless.


Accessible by default

Our palette was designed so that semantic pairings meet WCAG 2.1 contrast requirements out of the box. Text tokens paired with their corresponding background tokens achieve at least 4.5:1 contrast for normal text. Feedback colors — danger, success, warning, info — are tested in both themes to ensure legibility without relying on color alone.


Two-tier architecture

Primitive tokens define the raw color ramps (e.g. --color-blue-600). Semantic tokens reference primitives and assign them to interface roles (e.g. --color-action-primary maps to --color-blue-600 in light mode). Components only use semantic tokens — this indirection is what makes theming, dark mode, and brand customisation possible without touching component code.


Anatomy

The color system has two layers. Primitives are the full palette of available values. Semantic tokens map those values to roles within the interface.

Primitive
--color-blue-600
--color-red-600
--color-gray-900
Semantic
--color-action-primary
--color-action-destructive
--color-text-default

Semantic roles

Semantic tokens are grouped into seven categories. Each category addresses a different part of the interface.

CategoryPurposeExample token
BackgroundPage and container fills--color-background-default
TextBody copy, labels, links--color-text-default
ActionButtons and interactive controls--color-action-primary
BorderDividers, outlines, focus rings--color-border-default
FeedbackAlerts, banners, validation--color-feedback-danger-bg
SurfaceLayered containers (base, raised, overlay)--color-surface-raised
IconIconography in all states--color-icon-default

Usage guidelines

Use semantic tokens, never primitives

Components must always reference semantic tokens. Primitives exist to feed the semantic layer — they should not appear in component CSS. This rule ensures that every component automatically adapts to theme changes.

color: var(--color-text-default);

background: var(--color-background-subtle);

✓ Do

Reference semantic tokens so components adapt to theme changes automatically.

color: #282828;

background: var(--color-gray-50);

✕ Don't

Hardcoded hex values or primitive tokens break theming.


Match token role to element purpose

Choose tokens that match the semantic role of the element. A background should use a background token, not a surface token repurposed.

ElementCorrect tokenWrong token
Page fill--color-background-default--color-surface-base
Error message text--color-feedback-danger-text--color-text-danger on a plain background
Disabled input border--color-border-disabled--color-gray-200
Primary button fill--color-action-primary--color-blue-600

Action token patterns

Interactive elements follow a consistent three-state pattern: rest, hover, and active. Each variant (primary, secondary, ghost, destructive) provides all three plus a text color. See the Code tab for implementation examples.


Feedback tokens come in sets

Each feedback category (danger, success, warning, info) provides a background, text, and border token designed to work together. Always use the complete set. See the Code tab for implementation examples.


Dark mode

Arch UI supports light and dark themes through the same semantic token names. When [data-theme="dark"] is applied, the token values are remapped to dark-appropriate primitives. No component code changes are needed.

Light
background-default → white
text-default → gray-900
action-primary → blue-600
border-default → gray-200
Dark
background-default → gray-900
text-default → gray-50
action-primary → blue-500
border-default → gray-700

The general pattern: light mode uses darker primitives for foreground and lighter ones for background, while dark mode inverts this relationship. Accent colors shift toward lighter shades in dark mode to maintain contrast against dark surfaces.


Accessibility

Contrast requirements

All semantic text-on-background pairings meet WCAG 2.1 AA requirements:

  • Normal text (below 18px or below 14px bold): 4.5:1 minimum
  • Large text (18px+ or 14px+ bold): 3:1 minimum
  • UI components and graphical objects: 3:1 minimum against adjacent colors

Do not rely on color alone

Color should reinforce meaning, not be the sole indicator. Combine color with text labels, icons, or patterns to ensure information is perceivable by users with color vision deficiencies.

Red border and an error icon and descriptive text.

✓ Do

Combine color with icons and descriptive text for validation errors.

A red border as the only indicator that a field is invalid.

✕ Don't

Don't rely on color alone to signal state.


Focus visibility

All interactive elements must show a visible focus indicator using --color-border-focus. This token maps to --color-blue-500 (#068BEE) in light mode and --color-blue-400 (#6DAAFB) in dark mode, both providing strong contrast against their respective background colors. See the Code tab for the recommended focus style.