Guide 05

Tokens, export & preview

The generator's real output is not a picture of a palette. It is a set of named values that a codebase can consume without anyone retyping a hex code.

Name by role, never by appearance

--blue-600 is a primitive. It describes what the colour is. --color-action-primary is a semantic token. It describes what the colour does. Components should only ever reference semantics, because the day marketing decides the brand is green, a primitive named --blue-600 holding a green value is worse than no name at all.

A three-tier structure holds up well in practice:

  • Primitives — --violet-500, --neutral-950. Raw values, no opinions, never referenced by a component.
  • Semantics — --surface-1, --text-muted, --border-strong, --action-primary-hover. Theme-aware aliases pointing at primitives.
  • Component tokens — --button-bg, --input-border. Optional, and only worth adding when a component genuinely needs to diverge.

Two naming habits that prevent pain later: put the state at the end (--action-primary-hover, not --hover-action-primary) so tokens sort together alphabetically, and never encode the theme in the name (--surface-dark is a dead end the moment you add a third theme).

HEX, RGB or HSL — pick per use, not per project

Choosing an output notation
NotationStrengthsWeaknessesUse when
HEX #7C5CFFCompact, universally understood, pastes into any design toolUnreadable as a relationship; no alpha without 8-digit formHandoff, documentation, anything a designer will read
RGB rgb(124 92 255)Direct alpha via the slash syntax; matches canvas and image pipelinesHard to adjust by hand meaningfullyOverlays, shadows, anything needing transparency
HSL hsl(252 100% 68%)Human-editable; lightness and saturation ramps are obviousNot perceptually uniform across huesGenerated ramps, quick manual tweaks, theming maths
OKLCH oklch(0.64 0.22 288)Perceptually even lightness; better gradient interpolationNeeds a modern browser; less familiar to reviewNew projects on evergreen browsers only

Curiosityjivar emits all four for every token, so the choice stays a per-file decision rather than a migration.

What a CSS export should look like

:root {
  /* primitives */
  --violet-500: #7C5CFF;
  --violet-600: #6B49F2;
  --neutral-50:  #F7F8FC;
  --neutral-950: #0A0B14;

  /* semantics — light */
  --surface-1: var(--neutral-50);
  --text-strong: var(--neutral-950);
  --action-primary: var(--violet-500);
  --action-primary-hover: var(--violet-600);
}

:root[data-theme="dark"] {
  --surface-1: #141726;
  --text-strong: #EEF0F8;
  --action-primary: #8F73FF;
  --action-primary-hover: #A288FF;
}

The same data exported as JSON is what feeds contrast regression tests, native app builds and documentation pages. Keep one source of truth and generate every format from it; two hand-maintained copies will diverge within a month.

Copy behaviour that does not annoy people

Small details decide whether a copy button gets used. Copy the value only — no trailing semicolon, no quotes, no token name unless the user asked for it. Confirm the action visibly and briefly, with a status message that assistive technology announces rather than a colour change alone. Let the user switch notation before copying instead of copying the wrong format and forcing a conversion. And support copying a whole group at once, because nobody wants to click twenty-four buttons.

What a live preview is actually for

A row of swatches tells you very little. Colours only reveal their problems in context: at the size they will be used, adjacent to the colours they will sit next to, behind the type you will actually set. A useful preview therefore needs to include the four situations where palettes fail.

  • Dense text on a surface — a full paragraph, not a heading, at your real body size.
  • A 1px border between two surfaces — the fastest way to see whether your border token is doing anything at all.
  • An interactive element in every state — default, hover, focus, active, disabled, rendered simultaneously rather than one at a time.
  • A destructive action next to a primary one — where semantic red meets brand colour, and where the two most often clash.

The preview on our home page is deliberately narrow in scope: it proves the tokens are internally consistent, not that they suit your product. Treat it as a first filter. The real test is pasting the export into your own codebase and looking at a page you already know well — you will spot a wrong border colour in a familiar layout in seconds, and never in a demo.

Versioning the palette

Tokens are code. Commit them, review changes in pull requests, and write down why a value moved. A colour changed "because it looked better" is impossible to defend six months later when someone asks whether they can change it back. A colour changed "to raise the input border from 2.4:1 to 3.1:1" answers itself. See contrast and accessibility for the checks worth automating.