Skip to main content

Core · Show content

Code

Shows code inside a sentence, or in a block with syntax colours in every mode.

Example

Code blocks in the three modes, with the same scheme in each.

.panel {
  padding: var(--luz-space-md);
  color: var(--luz-text-primary);
  background: var(--luz-surface);
}
<button
  class="luz-btn luz-btn--primary"
  type="button">
  Save changes
</button>
import { MidiPlayer }
  from "@luz-ds/core/midi";

const player = await MidiPlayer.load(url);
player.play();

Inline code looks like var(--luz-text-primary) inside a sentence.

Syntax colours in the three modes

LUZ's own scheme: keywords stay ink and bold, colour goes to what the author wrote (names, properties, values), comments step back in italic. No red, because red means error.

Each colour keeps 4.5:1 or more on the block, 7:1 or more in high contrast.

TokenClassWhat it marks
--luz-code-comment
.tok-comment
Comments in every language. Muted and italic.
--luz-code-keyword
.tok-keyword
JavaScript and shell keywords, CSS at-rules and !important, the HTML doctype. Ink and bold, no colour.
--luz-code-name
.tok-name
HTML tags, CSS selectors and functions, JavaScript function and class names, shell commands.
--luz-code-property
.tok-property
HTML attributes, CSS properties and custom properties, JSON keys, shell flags and variables.
--luz-code-string
.tok-string
Quoted strings in every language, HTML attribute values.
--luz-code-literal
.tok-literal
Numbers and units, hex colours, true, false, null, HTML entities.

Light

/* Wide cards */
@media (min-width: 48rem) {
  .card::after {
    content: "new";
    inset: 0 auto auto 50%;
    color: var(--ink, #036);
  }
}
<!doctype html>
<!-- Primary action -->
<button type="submit" disabled>
  Save &amp; close
</button>
// Play a track
const player = await
  MidiPlayer.load("a.mid");
if (player) player.play(0, true);
{
  "name": "@luz-ds/core",
  "private": false,
  "size": 7.02
}
# Build and test
pnpm core:build
npx playwright test \
  --project=chromium $CI

Dark

/* Wide cards */
@media (min-width: 48rem) {
  .card::after {
    content: "new";
    inset: 0 auto auto 50%;
    color: var(--ink, #036);
  }
}
<!doctype html>
<!-- Primary action -->
<button type="submit" disabled>
  Save &amp; close
</button>
// Play a track
const player = await
  MidiPlayer.load("a.mid");
if (player) player.play(0, true);
{
  "name": "@luz-ds/core",
  "private": false,
  "size": 7.02
}
# Build and test
pnpm core:build
npx playwright test \
  --project=chromium $CI

High contrast

/* Wide cards */
@media (min-width: 48rem) {
  .card::after {
    content: "new";
    inset: 0 auto auto 50%;
    color: var(--ink, #036);
  }
}
<!doctype html>
<!-- Primary action -->
<button type="submit" disabled>
  Save &amp; close
</button>
// Play a track
const player = await
  MidiPlayer.load("a.mid");
if (player) player.play(0, true);
{
  "name": "@luz-ds/core",
  "private": false,
  "size": 7.02
}
# Build and test
pnpm core:build
npx playwright test \
  --project=chromium $CI

Known issues

The highlighter is a set of patterns, not a parser: JSX tags, the contents of HTML style and script elements and unquoted attribute values stay plain. The colours are decoration only: assistive technology reads the code the same way.

Code

Copy the markup

A bare pre needs no class: monospace type, a muted surface and a border.

HTML
<pre><code>npm install @luz-ds/core</code></pre>

.luz-code-block adds the language badge and the colors of the highlight. With the class:

HTML
<pre class="luz-code-block" data-lang="css" tabindex="0" role="region" aria-label="Panel styles"><code>.panel {
  color: var(--luz-text-primary);
}</code></pre>
HTML
<p>Set the colour with <code class="luz-code-inline">--luz-text-primary</code>.</p>
JS
import { initHighlight } from "@luz-ds/core/highlight";
initHighlight();

Variants and options

Two classes, and the language in an attribute.

Class or attributeEffect
.luz-code-block
A block on the muted surface, mono font, scrolls sideways when a line is long
.luz-code-inline
Code inside a sentence, in the code colour
data-lang
The language: html, css, js, jsx, json, bash, sh or shell. Shown as a label on its own line above the code, at the end edge. Any other value is shown, not highlighted

How it works

A <pre> with a <code> inside, styled by components/code.css. Highlighting is optional, from highlight.js.

  • highlightBlock(pre) colours one block: it wraps the code in six .tok-* classes, one per --luz-code-* token.
  • initHighlight() does it for every pre.luz-code-block, adds an aria-label to a block that has none ("CSS example"), and adds a copy button inside each block. Core gives that button no position: place it with your own CSS, or call highlightBlock() alone. luz.js runs initHighlight().
  • In forced colors every colour becomes the system text colour; bold keywords and italic comments stay.

Without JavaScript

The block is plain, readable text in one colour. Nothing is lost but the colours.

Keyboard and ARIA

A block can be wider than the screen, so it must take focus: Tab reaches it and the arrow keys scroll it.

  • tabindex="0", role="region" and an aria-label that names the code, so the focus stop has a name.
  • Inline code needs nothing.

Contrast and focus are in the Design tab.

Design

When to use

Use a code block for code or terminal output the reader may read or copy, and inline code for names inside a sentence.

When not to use

Do not use a code block for a long file or for text that is not code.

  • For a whole file, link to the source.
  • For a key the reader presses, use <kbd>.

Do and don't

Do Code that works when it is pasted: the command alone.
Don't A prompt sign and the output in the same block: pasted, the “$” and the output lines fail.

Writing the content

Show code that works when it is pasted.

  • Name each block in its aria-label: what the code is, not "Code".
  • Set data-lang; use text for output that is not code.
  • Keep lines short: a long line makes the reader scroll sideways.

Contrast and focus

The code and its syntax colours sit on the muted surface. In high contrast every syntax colour reaches 7:1.

PartColour on backgroundLightDarkHigh contrastNeeds
Code
--luz-text-primary on --luz-surface-muted
15.8:1
15.1:1
20.1:1
4.5:1
Comment
--luz-code-comment on --luz-surface-muted
5.0:1
8.5:1
8.7:1
4.5:1
Keyword
--luz-code-keyword on --luz-surface-muted
15.8:1
15.1:1
20.1:1
4.5:1
Name
--luz-code-name on --luz-surface-muted
8.8:1
12.0:1
13.5:1
4.5:1
Property
--luz-code-property on --luz-surface-muted
5.6:1
8.1:1
9.7:1
4.5:1
String
--luz-code-string on --luz-surface-muted
8.2:1
9.0:1
8.3:1
4.5:1
Literal
--luz-code-literal on --luz-surface-muted
6.7:1
8.4:1
11.1:1
4.5:1
Language label
--luz-text-secondary on --luz-surface-muted
6.2:1
7.5:1
18.4:1
4.5:1
Inline code
--luz-color-code on --luz-surface-muted
5.3:1
8.1:1
9.0:1
4.5:1

Measured from the token values of each mode, rounded down. Needs is the WCAG 2.2 AA minimum: 4.5:1 for text, 3:1 for focus rings, borders and icons.

  • Focus: core draws no ring of its own on a scrollable block (tabindex="0"): it gets the browser's. These docs add the LUZ ring in reference.css; do the same if your blocks scroll.
  • Not colour alone: keywords are bold and comments italic, so the syntax still reads without the colours.

Tokens it uses

The 21 tokens that components/code.css reads, by family. Each family links to its page, with the values in every mode. In Figma they are variables with the same names: see Tokens in Figma.

Spacing and sizing
--luz-space-2xs, --luz-space-3xs, --luz-space-md, --luz-space-sm
Typography
--luz-font-mono, --luz-text-sm, --luz-text-xs
Radius
--luz-radius-md, --luz-radius-sm
Motion
--luz-duration-base

Keyboard and ARIA are in the Code tab.