> ## Documentation Index
> Fetch the complete documentation index at: https://opencanvas.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Manage Design Tokens with CSS Variables

> Read and write CSS custom properties on the canvas iframe :root to maintain a consistent color, spacing, and typography scale across every component.

Design tokens — shared values for color, spacing, typography, and shadow — are the connective tissue that keeps a design system coherent. In DesignJS, tokens live as CSS custom properties on the canvas iframe's `:root` element. The `get_variables` tool reads the current token map, and `set_variables` writes or merges new values into it. Changes persist to `.designjs.json` under `cssVariables` and are re-applied every time the canvas reloads, so your token definitions survive across sessions and travel with the file in version control.

## How tokens work in the canvas

Every CSS custom property you define on `:root` is available to any component on the canvas via `var(--token-name)`. Because the canvas iframe runs Tailwind v4, you can also reference tokens inside arbitrary Tailwind values: `bg-[var(--brand-primary)]` or `text-[var(--text-muted)]` resolve at render time.

The full token lifecycle:

```
set_variables called
      │
      ▼
:root { --brand-primary: #6366f1; } injected into iframe
      │
      ▼
All components using var(--brand-primary) update immediately
      │
      ▼
Persisted to .designjs.json → cssVariables
      │
      ▼
Re-applied on next canvas load
```

***

## Read the current token map

Before adding or changing tokens, read what's already defined:

```json theme={null}
// Tool call
{
  "tool": "get_variables",
  "params": {}
}

// Response
{
  "variables": {
    "--brand-primary": "oklch(0.55 0.2 260)",
    "--brand-secondary": "oklch(0.65 0.15 200)",
    "--text-base": "oklch(0.15 0.01 260)",
    "--text-muted": "oklch(0.5 0.01 260)",
    "--surface-1": "oklch(1 0 0)",
    "--surface-2": "oklch(0.97 0.005 260)",
    "--radius-sm": "0.375rem",
    "--radius-md": "0.5rem",
    "--radius-lg": "0.75rem",
    "--space-4": "1rem",
    "--space-6": "1.5rem",
    "--space-8": "2rem"
  }
}
```

The response is a flat `Record<string, string>` — every key is a CSS custom property name (including the `--` prefix) and every value is the raw CSS value string.

<Info>
  If the canvas has no variables set yet, `get_variables` returns an empty object `{}`. You're starting with a clean slate.
</Info>

***

## Write or update tokens

`set_variables` merges the variables you provide into the existing set. Existing keys are overwritten; keys you don't mention are preserved:

```json theme={null}
// Tool call — update the brand color and add a new shadow token
{
  "tool": "set_variables",
  "params": {
    "variables": {
      "--brand-primary": "#6366f1",
      "--brand-primary-hover": "#4f46e5",
      "--shadow-card": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)"
    }
  }
}

// Response — full updated map
{
  "variables": {
    "--brand-primary": "#6366f1",
    "--brand-primary-hover": "#4f46e5",
    "--brand-secondary": "oklch(0.65 0.15 200)",
    "--text-base": "oklch(0.15 0.01 260)",
    "--text-muted": "oklch(0.5 0.01 260)",
    "--surface-1": "oklch(1 0 0)",
    "--surface-2": "oklch(0.97 0.005 260)",
    "--radius-sm": "0.375rem",
    "--radius-md": "0.5rem",
    "--radius-lg": "0.75rem",
    "--space-4": "1rem",
    "--space-6": "1.5rem",
    "--space-8": "2rem",
    "--shadow-card": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)"
  }
}
```

The response always returns the full updated map, so you can verify what's in effect after the call.

<Warning>
  There is no `delete_variables` tool. To remove a token, you currently need to edit `.designjs.json` directly and reload the canvas. Alternatively, set the variable to `unset` or an empty string to neutralize its effect in components.
</Warning>

***

## Complete workflow: rebrand a design

This example shows a full token-driven rebrand — switching a design from an indigo palette to a violet one without touching any individual component.

<Steps>
  <Step title="Read the current token map">
    ```json theme={null}
    {
      "tool": "get_variables",
      "params": {}
    }

    // Response
    {
      "variables": {
        "--brand-primary": "oklch(0.55 0.2 260)",
        "--brand-primary-hover": "oklch(0.50 0.22 260)",
        "--brand-accent": "oklch(0.70 0.18 260)",
        "--text-base": "oklch(0.15 0.01 260)",
        "--text-muted": "oklch(0.5 0.01 260)",
        "--surface-1": "oklch(1 0 0)",
        "--surface-2": "oklch(0.97 0.005 260)"
      }
    }
    ```

    Hue `260` in oklch is indigo. To shift to violet, move the hue to `290`.
  </Step>

  <Step title="Apply the new brand palette">
    ```json theme={null}
    {
      "tool": "set_variables",
      "params": {
        "variables": {
          "--brand-primary": "oklch(0.55 0.2 290)",
          "--brand-primary-hover": "oklch(0.50 0.22 290)",
          "--brand-accent": "oklch(0.70 0.18 290)"
        }
      }
    }
    ```

    Every component that references `var(--brand-primary)` updates immediately in the canvas iframe.
  </Step>

  <Step title="Verify visually with a screenshot">
    ```json theme={null}
    {
      "tool": "get_screenshot",
      "params": {
        "scale": 2,
        "format": "png"
      }
    }
    ```

    If the rebrand looks correct, press `Cmd+S` to persist the new token values to `.designjs.json`.
  </Step>
</Steps>

***

## Referencing tokens in components

There are two ways to use a token in a canvas component:

**1. Direct CSS custom property reference**

Pass the `var()` expression as a CSS value in `update_styles`:

```json theme={null}
{
  "tool": "update_styles",
  "params": {
    "componentId": "comp-btn-primary",
    "styles": {
      "background-color": "var(--brand-primary)",
      "border-radius": "var(--radius-md)"
    }
  }
}
```

**2. Tailwind arbitrary value syntax**

Because the canvas iframe runs Tailwind v4, you can use `var()` inside arbitrary value brackets in the HTML you pass to `add_components`:

```json theme={null}
{
  "tool": "add_components",
  "params": {
    "html": "<button class=\"bg-[var(--brand-primary)] hover:bg-[var(--brand-primary-hover)] text-[var(--text-base)] rounded-[var(--radius-md)] px-6 py-3 font-semibold\">Subscribe</button>"
  }
}
```

This keeps your HTML declarative and means a single `set_variables` call repaints every element that uses the token.

***

## Token naming conventions

Consistent naming makes tokens easier to use across components and easier to reference in agent prompts. A recommended pattern:

```
--{category}-{variant}
```

| Category     | Example names                                                |
| ------------ | ------------------------------------------------------------ |
| Brand colors | `--brand-primary`, `--brand-secondary`, `--brand-accent`     |
| Text         | `--text-base`, `--text-muted`, `--text-inverse`              |
| Surface      | `--surface-1`, `--surface-2`, `--surface-overlay`            |
| Border       | `--border-subtle`, `--border-strong`                         |
| Radius       | `--radius-sm`, `--radius-md`, `--radius-lg`, `--radius-full` |
| Spacing      | `--space-2`, `--space-4`, `--space-6`, `--space-8`           |
| Shadow       | `--shadow-sm`, `--shadow-card`, `--shadow-modal`             |

<Tip>
  When prompting an agent to add components, mention tokens by name: "Use `var(--brand-primary)` for the button background." The agent will use the token reference rather than hard-coding a hex value, so the component automatically participates in any future rebrands.
</Tip>

***

## About oklch values

The canvas uses [oklch](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch) as its preferred color format. oklch is perceptually uniform — equal changes in lightness or chroma look visually equal across the spectrum — which makes it well-suited for generating palette variants programmatically.

The format is `oklch(lightness chroma hue)`:

| Parameter   | Range          | Effect                                                        |
| ----------- | -------------- | ------------------------------------------------------------- |
| `lightness` | `0` to `1`     | `0` = black, `1` = white                                      |
| `chroma`    | `0` to \~`0.4` | `0` = grey, higher = more saturated                           |
| `hue`       | `0` to `360`   | Color angle: `0` red, `120` green, `260` indigo, `290` violet |

To generate a full tonal scale for a brand color, vary lightness while holding chroma and hue constant:

```json theme={null}
{
  "tool": "set_variables",
  "params": {
    "variables": {
      "--brand-50":  "oklch(0.97 0.04 260)",
      "--brand-100": "oklch(0.93 0.07 260)",
      "--brand-200": "oklch(0.85 0.10 260)",
      "--brand-300": "oklch(0.75 0.14 260)",
      "--brand-400": "oklch(0.65 0.17 260)",
      "--brand-500": "oklch(0.55 0.20 260)",
      "--brand-600": "oklch(0.47 0.22 260)",
      "--brand-700": "oklch(0.40 0.22 260)",
      "--brand-800": "oklch(0.32 0.18 260)",
      "--brand-900": "oklch(0.22 0.12 260)",
      "--brand-950": "oklch(0.14 0.07 260)"
    }
  }
}
```

***

## Persistence and version control

Token values are stored under `cssVariables` in `.designjs.json`:

```json theme={null}
{
  "cssVariables": {
    "--brand-primary": "oklch(0.55 0.2 260)",
    "--text-base": "oklch(0.15 0.01 260)",
    "--surface-1": "oklch(1 0 0)",
    "--radius-md": "0.5rem"
  },
  "components": [...]
}
```

Because `.designjs.json` is plain JSON, token changes produce clean, readable git diffs — the exact keys that changed are visible line by line. This makes design-token changes reviewable in a pull request alongside the component changes that use them.

***

## Next steps

<CardGroup cols={2}>
  <Card title="Design with an agent" icon="wand-sparkles" href="/guides/design-with-agent">
    Use tokens in a full agent-driven design session — add components that reference your token names from the start.
  </Card>

  <Card title="Export to React" icon="file-code" href="/guides/export-to-react">
    Export canvas components to `.tsx` files. Tailwind arbitrary values using `var()` tokens carry over directly.
  </Card>
</CardGroup>
