Theme Slots

Every surface a theme can re-point, with the mixin that sets it: semantic channels, component slots, utility remaps, border lines, and the chart ramp. Slots take token references, so each one still resolves through the device mode at render time.

#

Semantic channels

The semantic channels are the preferred API: a few lines re-theme the whole screen, and every component that reads a channel follows. The channels are a fixed set:

  • semantic-bg($semantic, $token): points a background channel at a token.
  • semantic-text($semantic, $token): points a text channel at a token, carrying the full text paint (ink, tile, clip).
  • semantic-stroke($semantic, $token): points the stroke channel at a token.
  • semantic-border($semantic, $token): points a border channel at a token's fill paint.
  • semantic-icon($token): optional paint for adaptive icons; omit it and icons follow text-primary.

Every semantic mixin takes $raw: true, which points the channel at a root palette variable and skips the mode pipeline. The framework uses it for its own unthemed dark defaults, where the dark remap would invert the value a second time. Theme files have no use for it; see Authoring Themes .

@include theme-slots.semantic-bg("canvas", "yellow");
@include theme-slots.semantic-bg("surface", "yellow");
@include theme-slots.semantic-text("text-primary", "black");
@include theme-slots.semantic-text("text-secondary", "yellow-30");
@include theme-slots.semantic-stroke("stroke-contrast", "yellow");
@include theme-slots.semantic-border("border-muted", "yellow-30");
#

Component slots

Component slots tune one surface without moving a whole channel. A slot name is the variable fragment a component reads, and each slot takes one kind of paint. These are the slots components consume today:

  • Background slots: screen-backdrop, title-bar, item-meta, item-meta-emphasis-2, item-meta-emphasis-3, progress-track, progress-fill, progress-fill-emphasis-2, progress-fill-emphasis-3, progress-dot, progress-dot-current, table-meta, table-meta-device, chip
  • Text slots: label-gray, chip
  • Border slots: table-head-row, table-body-row, label-underline

chip is a pair, one background slot and one text slot for the same surface: a solid marker box with readable text on it, for plugin surfaces the framework has no component for. It is the only slot whose default names semantic channels instead of a token, taking its field from fill-strong and its text from text-inverse. State both halves in a theme when the marker box needs its own pairing, the way White and Red gives it a white field with red text.

Pointing a slot at a channel it does not take is silent. A background slot given text-slot writes four variables no component reads, and nothing on the screen changes.

  • bg-slot($slot, $token): a slot's background paint.
  • text-slot($slot, $token): a slot's text paint, including the tile and clip.
  • border-level-slot($slot, $level, $dir: h): points a slot's border at one of the framework border levels.
  • border-token-slot($slot, $token, $dir: h): points a slot's border at a token's fill paint instead of a level.

Slot values cascade from the screen, so you can set them again on a component or state wrapper. On unthemed screens the inverse class supplies local defaults for the opposite of the screen's scheme. Inside a theme the subtree keeps the theme's slots, and the theme's inverse rule restates the ones that flip with the ground.

@include theme-slots.bg-slot("title-bar", "yellow-40");
@include theme-slots.bg-slot("progress-fill", "yellow-55");
@include theme-slots.text-slot("label-gray", "yellow-30");
@include theme-slots.border-token-slot("label-underline", "yellow-30");

.screen--theme-example .inverse {
    @include theme-slots.bg-slot("progress-fill", "yellow-20");
}
#

Utility remaps

Utility remaps re-point the raw palette utilities (bg--*, text--*, text-stroke--*), so plugin markup that names gray tokens follows the theme without edits.

  • utility-remap-grayscale($to-hue, $side): the bulk remap of the whole grayscale ladder to a hue. $side: 'dark' (default) compresses grays into the hue's dark steps 10 to 40, keeps black as ink, and sends white to the hue; 'bright' compresses into steps 45 to 75, sends black to the hue, and keeps white; 'linear' maps gray steps 1:1 to hue steps. Strokes are the exception: the token sent to the hue takes the nearest hue step for its stroke instead (45 under bright, 40 under dark, 75 under linear), so outlines never dissolve into the canvas.
  • utility-remap-border-grayscale($to-hue, $side): the same idea for the two border line inks, recoloring the staggered patterns without touching their geometry.
  • utility-bg($token, $remap-to) / utility-text($token, $remap-to) / utility-stroke($token, $remap-to): remap one utility token, for exceptions on top of a bulk remap.
  • utility-border-token($level, $dir, $token): remap one border level and direction to a token's paint.
  • utility-border-level($level, $dir, $from-level): point one border level at another level's art, fields and render program included. This is the handle the 2-bit rail needs, where the four tones are literal in the line data and no token remap can reach them. Restating a level onto itself is not a no-op: it also pins that level to the family's own line polarity.

The three shipped themes show every side: Black and Yellow is a dark-side remap; White and Red is a bright-side remap plus one exception, utility-bg("white", "red"), so white surfaces adopt the canvas hue while white text stays ink. Dark mirrors the grayscale axis and leans on utility-border-level for the 2-bit rail and for the one level that maps to itself.

// White and Red: bright-side remap with one exception.
@include theme-slots.utility-remap-grayscale("red", $side: "bright");
@include theme-slots.utility-remap-border-grayscale("red", $side: "bright");
@include theme-slots.utility-bg("white", "red");
#

Border levels and lines

Border levels are the seven-step intensity scale the border pipeline renders: 1 is black, 2 through 6 step through the grays (gray-15, gray-30, gray-40, gray-50, gray-65), 7 is white, each with an h and a v direction. border-level-slot points a component slot at a level; utility-border-token re-points a level itself, and the bulk line remap recolors the two dither line inks. See Border and Divider for how levels render.

Every border slot and remap moves two outputs: the CSS background and the SVG render program that TRMNLPaint.border() and TRMNLPaint.divider() export. A slot bound to a level carries that level's pattern program. A slot or remap bound to a token exports a flat line in the token's stroke color, because a token line has no pattern program of its own.

#

The chart ramp

chart-series-ramp($tokens, $span: 6) publishes the theme's chart-series ramp. $tokens is an ordered list running from the strongest contrast against the canvas (series 0) toward the canvas tone; each slot aliases the token's own paint, so series inherit per-mode dithers and solids for free. $span is the legible front of the ramp that JavaScript spreads series across.

The ramp always publishes 16 slots, so a short list is safe: the slots past your last token are cleared rather than left holding the framework grayscale, and $span never reaches past that token.

Charts read the ramp through TRMNLPaint.series(); see Painting Charts and Chart .

@include theme-slots.chart-series-ramp((
    black, yellow-10, yellow-20, yellow-30, yellow-40, yellow-55, yellow-75, yellow
));