Skip to content
@erikakers/slate

The colour layer

Every --slate-color-* token, as a swatch rather than a number in a table: light and dark value side by side, with the contrast ratio Slate measures for the pairing the pair rules give it. The syntax palette has a page of its own, and the four theme blocks that carry all of these values are demonstrable live.

The palette

Twenty-four colours, declared once each as a light/dark pair in settings/_palette.scss and emitted into the four theme blocks by tools/_theme.scss.

  • --slate-color-bg#FCFCFD#0C0F14
  • --slate-color-bg-subtle#F1F3F7#13171E
  • --slate-color-bg-raised#E9EDF3#1B212A
  • --slate-color-bg-inset#F4F6F9#10141A
  • --slate-color-text#12161D#E7EBF1on --slate-color-bg 17.68:1 light · 16.04:1 darkPasses AA 1.4.3 (4.5:1)
  • --slate-color-text-muted#3C4654#B3BCC9on --slate-color-bg 9.33:1 light · 10.01:1 darkPasses AA 1.4.3 (4.5:1)
  • --slate-color-text-subtle#5D6777#8892A1on --slate-color-bg 5.58:1 light · 6.10:1 darkPasses AA 1.4.3 (4.5:1)
  • --slate-color-text-invert#FCFCFD#0C0F14on --slate-color-accent 7.56:1 light · 8.61:1 darkPasses AA 1.4.3 (4.5:1)
  • --slate-color-line#D2D8E2#232A34on --slate-color-bg 1.40:1 light · 1.33:1 darkDecorative: no threshold asserted (1.4.11 does not reach a separator).
  • --slate-color-line-soft#E4E8EF#1A2029on --slate-color-bg 1.20:1 light · 1.17:1 darkDecorative: no threshold asserted (1.4.11 does not reach a separator).
  • --slate-color-line-strong#AEB8C6#39434Fon --slate-color-bg 1.96:1 light · 1.91:1 darkDecorative: no threshold asserted (1.4.11 does not reach a separator).
  • --slate-color-line-control#778499#627082on --slate-color-bg 3.69:1 light · 3.80:1 darkPasses AA 1.4.11 (3:1)
  • --slate-color-accent#35547C#93B0D6on --slate-color-bg 7.56:1 light · 8.61:1 darkPasses AA 1.4.3 (4.5:1)
  • --slate-color-accent-hover#28425F#B0C6E4on --slate-color-bg 10.07:1 light · 11.01:1 darkPasses AA 1.4.3 (4.5:1)
  • --slate-color-accent-text#FFF#0C0F14on --slate-color-accent 7.75:1 light · 8.61:1 darkPasses AA 1.4.3 (4.5:1)
  • --slate-color-accent-bg#E7EDF6#18202C
  • --slate-color-accent-line#B9C9DE#2E3D52
  • --slate-color-good#2F6B52#7FBE9Con --slate-color-bg 6.12:1 light · 8.91:1 darkPasses AA 1.4.3 (4.5:1)
  • --slate-color-good-bg#E4EFE9#16241D
  • --slate-color-warn#8A5A2B#D5A87Aon --slate-color-bg 5.72:1 light · 8.88:1 darkPasses AA 1.4.3 (4.5:1)
  • --slate-color-warn-bg#F5ECE1#261E14
  • --slate-color-crit#8C3A3A#D98D8Don --slate-color-bg 7.36:1 light · 7.44:1 darkPasses AA 1.4.3 (4.5:1)
  • --slate-color-crit-bg#F6E6E6#271717
  • --slate-color-selection#D5E1F1#24354B

Measured, not claimed

Every ratio above is computed at build time by Slate's own slate-contrast function in src/tools/_contrast.scss: the docs site compiles pkg:@erikakers/slate with Dart Sass and reads the ratios out of the compiled output, through the same probe shape test/unit/contrast.test.js uses. The pages and the suite therefore read one source of truth; a number typed into a page instead would drift from the module the day a colour moves, which is the failure these pages exist to remove.

A pair below its documented threshold renders a visible fail flag, not merely a small number. One pair is deliberately exempt, and it is on the code page with its reason.

The pair rules

The thresholds are WCAG 2.2, and they are the ones contrast.guard() refuses the build on:

  • 4.5:1 for reading text at body size, WCAG 1.4.3: every reading colour on every surface, semantic colours on their own tinted grounds, the inverted accent pairs, and reading text on selection and on the crit tint.
  • 3:1 for a boundary that identifies a control, WCAG 1.4.11: --slate-color-line-control on all four surfaces, and on the accent tint that fills .slate-tag--accent.

Each foreground's row above shows its pairing on the page surface (--slate-color-bg), which is the documented pairing. The requirement lists assert more than the rows show: the reading colours are held to 4.5:1 as a cross product over all four surfaces, and the control boundary to 3:1 over the same four, checked on every build by contrast.guard() and by the suite.

The line tokens (--slate-color-line, -line-soft, -line-strong) are shown with their measurements and no flag: they are decorative, 1.4.11 does not reach a separator, and settings/_palette.scss records the reason beside the requirement list. A pair that carries no threshold is absent from the requirement list rather than present with a low number.

One declaration per colour

A colour is written once, as a (light:, dark:) pair, and tools/_theme.scss emits the four blocks from it; the values above are read out of the same compiled output. A pair is a map rather than a two-element list because two of the twenty-six values are shadows, and a shadow is itself a comma list.theme.validate() refuses an unprefixed name, a value that is not a pair, a pair missing a side, and a side that is not light or dark.

$slate-palette, $slate-shadow and $slate-code-palette carry !default; the invariant tokens in settings/_space.scss do not, and the asymmetry is about where the override lands. A consumer redeclaring --slate-space-5 in their own :root wins, because nothing restates it in a themed block; one redeclaring --slate-color-bg there loses the moment a theme is stamped, because :root[data-theme='dark'] outranks :root. So reaching a colour is a Sass configuration and reaching a length is not.

The two line tokens

The rule, for the next bordered component:

A border that a reader needs in order to tell a control from the page takes --slate-color-line-control. Everything else, a separator between two pieces of content, takes --slate-color-line. The test is not whether the element is interactive. It is whether the boundary is what identifies it.

--slate-color-line keeps its drawn value, 1.40:1 light and 1.33:1 dark on the page, decorative and deliberately unasserted. --slate-color-line-control is the value the rows above hold to 3:1 on every surface.

The shadows

The two shadow tokens, drawn as the values actually read (chip ground: --slate-color-bg).

  • --slate-shadow-sm0 1px 2px rgba(18, 22, 29, 0.05)0 1px 2px rgba(0, 0, 0, 0.4)shadow, no contrast requirement
  • --slate-shadow0 1px 2px rgba(18, 22, 29, 0.04), 0 8px 24px -12px rgba(18, 22, 29, 0.1)0 1px 2px rgba(0, 0, 0, 0.5), 0 8px 24px -12px rgba(0, 0, 0, 0.7)shadow, no contrast requirement

The four blocks, live

All of these values resolve through four theme blocks: the light base, OS dark, and the two stamped states. The theme model page renders the same content under all four with a reader-state control, so the override behaviour (a stamped attribute beats the OS preference) can be seen rather than described.