Cadence Clinical

Theming

Set the colour mode, contrast, density, accent and font, and add your own brand accent.

You theme Cadence with four attributes on the <html> element and two CSS variables. Status colours are not themeable.

<html data-mode="dark" data-contrast="more" data-density="comfortable" data-accent="indigo"></html>

Attributes

AttributeValuesWhen it is not set
data-modelight, darkFollows the operating system's prefers-color-scheme. The dark class also selects dark mode.
data-contraststandard, moreFollows the operating system's prefers-contrast.
data-densitycompact, comfortableCompact, or comfortable on a touch device.
data-accentteal, blue, indigo, violet, plum, slateteal

Set the attributes on <html> only. Cadence does not support a differently themed subtree.

Contrast

Standard contrast meets WCAG 2.2 AA: 4.5:1 for text and 3:1 for control boundaries. more raises those to 7:1 and 4.5:1.

Every pairing of tokens that a component relies on is asserted in the @cadence-clinical/tokens test suite, for each mode, contrast level and accent. A token change that lowers a pairing below its minimum fails the build.

Density

Compact is the default. Controls are 32px high, which suits a workstation with a mouse. Comfortable raises controls to 44px for touch screens, tablets and workstations on wheels.

Font

Cadence reads its fonts from two CSS variables. Without them it uses the system font stack.

:root {
  --cadence-font-sans: "Inter", sans-serif;
  --cadence-font-mono: "JetBrains Mono", monospace;
}

Status colours

critical, warning, success and info carry clinical meaning, so they are the same in every theme and no attribute changes them. Each status has five tokens:

TokenUse
criticalA solid fill.
critical-foregroundText and icons on the solid fill.
critical-subtleA tinted surface.
critical-textText on the page background or on the tinted surface.
critical-borderThe edge of any status surface.

Put the border token on every status surface. No amber fill reaches 3:1 against a white page, so without its border a warning surface has no perceivable edge.

Never signal status with colour alone. Pair it with text or an icon.

Add your own accent

An accent is brand colour only. It drives primary buttons, links and focus rings.

createAccent takes one brand colour and returns a complete accent. It keeps the hue and chroma, and solves the lightness of each role so that contrast holds in both modes and both contrast levels.

scripts/build-accent.ts
import { writeFile } from "node:fs/promises";
import { assertAccent, generateAccentCss } from "@cadence-clinical/tokens";

const definition = assertAccent("#0b5fff");
await writeFile("app/brand-accent.css", generateAccentCss("brand", definition));

Import the generated file after the Cadence styles, and set data-accent="brand" on <html>.

assertAccent throws when a colour cannot be made safe. Run it in your build so that an unsafe accent fails the build.

Colours Cadence rejects

Cadence rejects an accent whose hue is within 30° of critical red, warning amber or success green in OKLCH. On a clinical screen, a brand colour in those ranges can be read as a status. If your brand is red, amber or green, use slate or another curated accent, and keep the brand colour in your logo.

Greys are exempt from the hue check because a grey cannot be mistaken for a status.

On this page