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.
| Token | Class | What 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 & 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 & 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 & 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.
<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:
<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>
<p>Set the colour with <code class="luz-code-inline">--luz-text-primary</code>.</p>
import { initHighlight } from "@luz-ds/core/highlight";
initHighlight();
Variants and options
Two classes, and the language in an attribute.
| Class or attribute | Effect |
|---|---|
.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 everypre.luz-code-block, adds anaria-labelto 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 callhighlightBlock()alone.luz.jsrunsinitHighlight().- 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 anaria-labelthat 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
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; usetextfor 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.
| Part | Colour on background | Light | Dark | High contrast | Needs |
|---|---|---|---|---|---|
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 inreference.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.
- Color
--luz-code-comment,--luz-code-keyword,--luz-code-literal,--luz-code-name,--luz-code-property,--luz-code-string,--luz-color-code,--luz-divider,--luz-surface-muted,--luz-text-primary,--luz-text-secondary- 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.