Skip to content

Build panels

Theme tokens

The sixteen tokens Deska writes on every panel page, what each one is for, how the mode is decided, and how to keep a panel right in every theme and accent.

How theming works

When the panel says ready, and again whenever the person changes the theme or the accent, the SDK writes Deska’s theme on document.documentElement as CSS custom properties and sets color-scheme to match. Style with them and the panel looks right in dark, light and every accent, with no listener:

app.csscss
:root { color-scheme: dark light; }

body {
  margin: 0;
  background: var(--deska-bg);
  color: var(--deska-text);
  font: 13px/1.45 var(--deska-font-ui);
}

.card {
  background: var(--deska-surface);
  border: 1px solid var(--deska-border);
  border-radius: var(--deska-radius);
}

.hint { color: var(--deska-text-secondary); }

button.primary {
  background: var(--deska-accent);
  color: var(--deska-on-accent);
  border-radius: var(--deska-radius-small);
}

:focus-visible { outline: 2px solid var(--deska-focus); }

.error { color: var(--deska-danger); }
code { font-family: var(--deska-font-mono); }

Values are resolved before they are sent: a color is a solid rgb(), never a var() or a color-mix(). Where the app’s own color is translucent, Deska paints it over the panel’s ground first, so what you get is exactly what the person sees and safe to compute contrast from.

The tokens

TokenUse it for
--deska-bgThe panel’s ground: the page background.
--deska-surfaceCards, rows, inputs and anything that sits on the ground.
--deska-surface-raisedMenus, popovers and anything that floats over a surface.
--deska-textBody text, values and anything a person needs to decide.
--deska-text-secondaryLabels and supporting text.
--deska-text-tertiaryHints and placeholders the panel still works without.
--deska-accentThe one accent: the main action, a selection, a progress fill.
--deska-on-accentText and icons on an accent fill.
--deska-borderHairlines between rows and around inputs.
--deska-focusThe focus ring.
--deska-dangerErrors and destructive actions.
--deska-successDone, running, healthy.
--deska-font-uiThe interface font family.
--deska-font-monoCode, numbers in columns, ids.
--deska-radiusCards and larger surfaces.
--deska-radius-smallButtons, inputs and chips.

The list may grow, so style with the names you know and ignore the rest. The accent follows the person’s choice, so never assume it is coral. Theme Inspector shows every token live with its value and contrast, and copies a token’s var() with a click.

Dark or light

mode says which way the ground leans. Deska calls a theme light when the relative luminance of --deska-bg is above about 0.18 (0.179 exactly), the point where dark text starts to read better than white. Light themes with a tinted paper ground sit near 0.48, so a midpoint of 0.5 would have called them dark.

app.jsjs
const { mode, tokens } = deska.theme
const chartPalette = mode === 'light' ? LIGHT_SERIES : DARK_SERIES
const ground = tokens['--deska-bg']

Read mode for what tokens cannot carry, like a chart’s series colors or an image with a dark and a light version. For everything else, the tokens already are the right answer.

Colors outside CSS

A canvas, a WebGL scene or an SVG built in script cannot use var(). Read the resolved value from the document and redraw on the theme event:

chart.jsjs
function draw() {
  const css = getComputedStyle(document.documentElement)
  ctx.fillStyle = css.getPropertyValue('--deska-accent')
  ctx.strokeStyle = css.getPropertyValue('--deska-border')
  // ...
}

await deska.ready()
draw()
deska.on('theme', draw)

Contrast that holds

  • Put text people must read in --deska-text. --deska-text-secondary is for labels, and --deska-text-tertiary only for hints: in light themes it does not reach body text contrast on the ground.
  • Use the accent as a fill or a mark, with --deska-on-accent on top. As body text on the ground, a light theme’s accent can fall short too.
  • Do not fade a whole row to make it secondary: its actions and focus ring fade with it. Use a quieter text token instead.
  • Check both: switch Deska’s theme with the panel open, or flip the theme in the preview tool.
TipShip your own fonts as woff2 inside the package if you need one. Remote stylesheets, Google Fonts’ included, are refused by the sandbox; see The sandbox.