UX-DSL
XS0px

Palette

Semantic color mappings for primary, secondary, and surface roles.

Give colors a role in your UI.

UXDSL builds on standard CSS. Colors define the available color values; Palette assigns colors to interface roles. Both are configured in the theme JSON. Prefer palette() when a component expresses a role such as primary action or surface. Use color() when a specific color token is intentional, and standard CSS when finer control is needed.

A palette describes what a color is used for. Primary does not have to mean blue: another theme can assign a different color while components keep the same role.

1. Define Colors and Palette in the theme JSON

This reference excerpt defines a color collection and connects palette roles to it using CSS variable references:

{
  "colors": {
    "blue": { "500": "#3b82f6", "700": "#1d4ed8" },
    "white": "#ffffff",
    "ink": "#0f172a"
  },
  "palette": {
    "primary": {
      "main": "var(--uxdsl__color__blue-700)",
      "contrast": "var(--uxdsl__color__white)"
    },
    "surface": {
      "main": "var(--uxdsl__color__white)",
      "contrast": "var(--uxdsl__color__ink)"
    }
  }
}

The nested entry colors.blue["700"] produces --uxdsl__color__blue-700. The nested role palette.primary.main produces --uxdsl__palette__primary-main.

References preserve the connection. In this JSON, primary.main references blue-700. Changing that color updates the role once the theme is compiled or applied. A literal hex value in a palette is also valid, but copying a color’s hex value does not create a reference to that color token.

2. Express the intended role in components

UXDSL you write

.primary-action {
  background: palette(primary.main);
  color: palette(primary.contrast);
}

/* Deliberately use a specific color token */
.blue-swatch {
  background: color(blue-700);
}

Equivalent plain CSS

:root {
  --uxdsl__color__blue-700: #1d4ed8;
  --uxdsl__color__white: #ffffff;
  --uxdsl__palette__primary-main: var(--uxdsl__color__blue-700);
  --uxdsl__palette__primary-contrast: var(--uxdsl__color__white);
}

.primary-action {
  background: var(--uxdsl__palette__primary-main);
  color: var(--uxdsl__palette__primary-contrast);
}
.blue-swatch {
  background: var(--uxdsl__color__blue-700);
}

The CSS shows only the variables used by these two selectors. Plain CSS custom properties provide the same reference mechanism; UXDSL connects component syntax to the theme’s shared definitions.

3. Choose the scope of the change

  • Update a color value: change colors.blue["700"] to update direct consumers and palette roles that reference it.
  • Reassign a role: change palette.primary.main to reference blue-500. Primary actions follow that role; direct color(blue-700) consumers keep their token.
  • Change one component: choose another appropriate existing role or color token in that component, without changing shared definitions.

Apply changes through the theme build or supported runtime API. Existing overrides and active modes can affect the final value. A variant named contrast is a configured foreground color, not proof of accessible contrast; check the actual foreground/background pair in each relevant state and theme.

Explore roles in the live playground

Use the examples and palette editors below to inspect roles and their consumers. The reference JSON above stays unchanged. Palette edits may affect other parts of the playground that use the same role. Editor changes update the playground’s theme/runtime state; some controls persist browser overrides. They do not write to your source JSON file.

Read Colors to understand the values behind palette roles.

Interactive Demo: Palette
Background
Text
Live Palette Preview
CSS Usage
.my-element{
background:palette(primary-main);
color:palette(primary-contrast);
}

Token-Aware Colors: Use palette() to access semantic colors (primary, success, surface) and their variants (main, light, dark).

Palette Explorer

Primary

Brand actions and key highlights
main
light
dark
contrast

Click any swatch above to edit and apply the selected color.

Select Tone
Primary
Secondary
Tertiary
Success
Info
Warning
Error
Dark
Neutral
Light
Surface
Global Palette
Click on any color swatch to update the UX-DSL token.

Primary

Brand actions and key highlights

  • primary-main
  • primary-light
  • primary-dark
  • primary-contrast

Secondary

Complementary elements and secondary CTAs

  • secondary-main
  • secondary-light
  • secondary-dark
  • secondary-contrast

Tertiary

Muted accents and tertiary surfaces

  • tertiary-main
  • tertiary-light
  • tertiary-dark
  • tertiary-contrast

Success

Positive states and confirmations

  • success-main
  • success-light
  • success-dark
  • success-contrast

Info

Informational surfaces and banners

  • info-main
  • info-light
  • info-dark
  • info-contrast

Warning

Cautionary or pending actions

  • warning-main
  • warning-light
  • warning-dark
  • warning-contrast

Error

Destructive flows and error states

  • error-main
  • error-light
  • error-dark
  • error-contrast

Dark

High-contrast backgrounds

  • dark-main
  • dark-light
  • dark-dark
  • dark-contrast

Neutral

Structure, frames, and dividers

  • neutral-main
  • neutral-light
  • neutral-dark
  • neutral-contrast

Light

Raised backgrounds and cards

  • light-main
  • light-light
  • light-dark
  • light-contrast

Surface

Base canvas + sheets

  • surface-main
  • surface-light
  • surface-dark
  • surface-contrast

AI implementation guide

How an AI agent should use Palette

UXDSL builds on standard CSS. Colors define the available color values; Palette assigns colors to interface roles. Both are configured in the theme JSON. Prefer palette() when a component expresses a role such as primary action or surface. Use color() when a specific color token is intentional, and standard CSS when finer control is needed.

Responsibility: maintain the semantic roles consumed by UI components. Palette expresses purpose, such as primary action or surface, independently of the current color assigned to it.

  • Inspect palette, relevant mode overrides and component conventions before choosing a role and variant. Primary does not inherently mean blue.
  • Prefer palette(role.variant) when styling interface roles. Confirm the role, variant and any referenced Color exist in the intended theme.
  • Do not replace a Palette reference with a Color reference merely to reproduce the current visual result. Preserve the semantic layer when the component expresses a UI role.
  • Reassign a Palette role when its meaning stays the same but its visual color should change. Keep components connected to the role rather than rewriting their color declarations.
  • Use explicit CSS variable references in JSON when a role should follow a Color token. A literal color is independent; matching a Color token’s hex value does not link them.
  • For a change limited to one component, select an appropriate existing role or a deliberate local exception. Do not reassign a shared role unless its other consumers should change.
  • Update the Palette definition in the source theme or through its supported runtime API. Review mode-specific assignments so they preserve the intended role.
  • Verify consumers of the reassigned role, interaction states and modes. Confirm direct Color consumers remain unchanged. Check the actual foreground/background contrast; the variant name contrast is not automatic validation.

Decision rule: Prefer Palette when styling interface roles. Reassign a Palette role when the meaning stays the same but its visual color should change. Keep components connected to the role.

Preserve intent, not just the current computed value. A Palette role and a Color token can look identical today while responding differently to tomorrow’s theme changes.

Configuration and usage example

{
  "colors": {
    "blue": { "500": "#3b82f6", "700": "#1d4ed8" },
    "white": "#ffffff",
    "ink": "#0f172a"
  },
  "palette": {
    "primary": {
      "main": "var(--uxdsl__color__blue-700)",
      "contrast": "var(--uxdsl__color__white)"
    },
    "surface": {
      "main": "var(--uxdsl__color__white)",
      "contrast": "var(--uxdsl__color__ink)"
    }
  }
}
.primary-action {
  background: palette(primary.main);
  color: palette(primary.contrast);
}

The action consumes primary.main, which currently references blue-700. Reassign the role to another defined Color to update its consumers while keeping their semantic declarations intact.

Agent reasoning example

Change primary actions to use the existing blue-500 color.
  1. Confirm blue-500 exists and inspect the primary role, its consumers and mode overrides.
  2. Update palette.primary.main to var(--uxdsl__color__blue-500) in the intended theme scope.
  3. Keep components using palette(primary.main); leave direct blue-700 references unchanged.
  4. Apply the theme and verify affected actions, states and modes. Recheck the contrast foreground and adjust its definition if the design requires it.

Colors define the values. Palette defines their roles. Components express the intended use.