Skip to content

Code draft v0.1.1

The syntax highlighting colors of code, one per category, and the states of marked lines, readable on every surface in every mode.

Code samples, token paths and snippets are set in the mono family (Typography foundation); this foundation colors them. Each syntax category (keyword, variable, function, class and type, string, number, comment) has a semantic color from the Figma library's code colors, global.text.code; the design system adds colors for diffs, invalid code and links, and backgrounds for marked lines, all picked from colors it already has. Everything else in code (plain identifiers, operators, punctuation) keeps the primary on-base text color. A highlighter maps the categories of its grammars to these colors: on the web, a Shiki theme generated from the tokens does it once for every mode, and a style sheet draws the marked lines.

Specimens

The tokens this foundation is built from, drawn from packages/tokens/src/: raw primitives and the semantic decisions on top of them. A token added to one of these groups appears here with no site change; values that differ per mode or per platform are shown next to each other.

Syntax colors

One color per syntax category, and the additions for diffs, invalid code and links, with the palette step each aliases in every mode.

global.text.code.* · 12 tokens · Swatch, value and alias of each token in every mode, side by side.

Tokenlightdark
global.text.code.keyword
#7534A9
{extended.lavender.700}
#B87BF5
{extended.lavender.400}
global.text.code.variable
#923D78
{extended.orchid.700}
#F283CD
{extended.orchid.400}
global.text.code.function
#266280
{extended.azure.700}
#5BB8E7
{extended.azure.400}
global.text.code.class-and-type
Decision code-colors-contrast (Code foundation): the Figma library extended.amber.500 is 1.96:1 on global.bg.level.1.default, under the 4.5:1 of WCAG 1.4.3.
#7F6426
{extended.amber.700}
#EEB836
{extended.amber.400}
global.text.code.string
Decision code-colors-contrast (Code foundation): the Figma library extended.forest.600 is 3.80:1 on global.bg.level.1.default.
#18614E
{extended.forest.700}
#68BBA1
{extended.forest.400}
global.text.code.number
Decision code-colors-contrast (Code foundation): the Figma library extended.coral.500 is 3.21:1 on global.bg.level.1.default, coral 600 still 4.30:1.
#9C4324
{extended.coral.700}
#FD8C67
{extended.coral.400}
global.text.code.comment
#4C4A4A
{light-switch.base.700}
#9D9B9C
{dark-switch.base.300}
global.text.code.inserted
Lines a diff adds. The on-base success text step.
#075D33
{functional.success.700}
#11C772
{functional.success.300}
global.text.code.deleted
Lines a diff removes. The step of error text on tinted fills: on-base error (error 500) is 4.26:1 on level 1.
#C01619
{functional.error.600}
#FAA79D
{functional.error.200}
global.text.code.changed
Lines a context diff changes. The on-base severe text step.
#764016
{functional.severe.700}
#FE8400
{functional.severe.300}
global.text.code.invalid
Code a grammar marks invalid or deprecated. Same step as deleted.
#C01619
{functional.error.600}
#FAA79D
{functional.error.200}
global.text.code.link
URLs and links in code and markup. The on-base brand text step.
#175DD6
{brand.light.600}
#9EE7FA
{brand.dark.200}

Line backgrounds

Backgrounds of marked lines, aliasing the subtle fills.

global.bg.code.* · 5 tokens · Swatch, value and alias of each token in every mode, side by side.

Tokenlightdark
global.bg.code.highlighted
A line the author points out.
#EEF1F7
{global.bg.subtle.brand.default}
#09191D
{global.bg.subtle.brand.default}
global.bg.code.inserted
A line an example adds.
#DBFAE6
{global.bg.subtle.functional.success.default}
#011C16
{global.bg.subtle.functional.success.default}
global.bg.code.deleted
A line an example removes.
#FEECEA
{global.bg.subtle.functional.error.default}
#2B0B08
{global.bg.subtle.functional.error.default}
global.bg.code.error
A line in error.
#FEECEA
{global.bg.subtle.functional.error.default}
#2B0B08
{global.bg.subtle.functional.error.default}
global.bg.code.warning
A line with a warning.
#FFF1C7
{global.bg.subtle.functional.warning.default}
#1F1504
{global.bg.subtle.functional.warning.default}

Examples

Code samples from packages/components/specs/foundations/code/, highlighted with the design system's Shiki theme, generated from the tokens. A sample follows the page mode; set another mode context to compare, as in a component's playground.

/**
 * Contrast between two colors, as WCAG defines it.
 * Every category of the syntax shows here: keywords, variables,
 * functions, classes, strings, numbers and comments.
 */
import { readFile } from 'node:fs/promises';

const HEX = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i;
const MINIMUM = { text: 4.5, large: 3, ui: 3 };

export class Color {
  #channels;

  constructor(r, g, b, alpha = 1) {
    this.#channels = [r, g, b].map((c) => Math.min(1, Math.max(0, c)));
    this.alpha = alpha;
  }

  static fromHex(hex) {
    const match = HEX.exec(hex.trim());
    if (!match) throw new TypeError(`"${hex}" is not a six-digit hex color`);
    const channels = match.slice(1).map((pair) => parseInt(pair, 16) / 255);
    return new Color(...channels);
  }

  get luminance() {
    const linear = (c) => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);
    const [r, g, b] = this.#channels.map(linear);
    return 0.2126 * r + 0.7152 * g + 0.0722 * b;
  }
}

export function contrast(foreground, background) {
  const [light, dark] = [foreground, background]
    .map((color) => color.luminance)
    .sort((a, b) => b - a);
  return (light + 0.05) / (dark + 0.05);
}

export async function audit(file, { kind = 'text', signal } = {}) {
  const text = await readFile(file, { encoding: 'utf8', signal });
  const pairs = JSON.parse(text);
  const failing = [];
  for (const { fg, bg, name = 'unnamed' } of pairs) {
    const ratio = contrast(Color.fromHex(fg), Color.fromHex(bg));
    if (ratio < MINIMUM[kind]) {
      failing.push({ name, ratio: Number(ratio.toFixed(2)) });
    }
  }
  return failing.length === 0 ? null : failing;
}
packages/components/specs/foundations/code/contrast.js