Theme Slots
This page lists every slot: each part of a screen a theme can recolor, and the mixin that sets it. A slot takes a framework token, not a raw color, so whatever you map still renders correctly on every device.
Semantic Channels
Start with the semantic channels: a few lines recolor the whole screen, because every component reads them. The set is fixed:
- Backgrounds:
canvas,surface,backdrop,fill-strong,fill-muted,fill-soft - Text:
text-primary,text-secondary,text-inverse - Stroke:
stroke-contrast - Borders:
border-strong,border-muted - Icon: one global channel for
image--adaptiveicons; it defaults to text-primary. See Image Image Place images with size, object fit, dithering, inversion, and adaptive icon utilities Place images on a screen and control their size, object fit, and inversion. On 1-bit displays, dithering arranges black and white pixels so an image still reads as shades of gray. .
-
semantic-bg($semantic, $token): sets a background channel to a token. -
semantic-text($semantic, $token): sets a text channel to a token, with everything text needs (color, dither pattern, clipping). -
semantic-stroke($semantic, $token): sets the stroke channel to a token. -
semantic-border($semantic, $token): sets a border channel to a token's fill. -
semantic-icon($token): optional color for adaptive icons; omit it and icons follow text-primary.
Every semantic mixin takes $raw: true, which
writes a plain color and skips device rendering; a theme never needs 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 recolor one surface, like the title bar, without moving a whole channel. Each slot is named after the part it colors and takes one kind of paint. These are the slots components read 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 two slots for one surface: a solid
box with readable text on it, for markers the framework has no component for. Its defaults point at the
semantic channels (box from fill-strong,
text from text-inverse), so it follows the
theme on its own. Set both halves yourself when the box needs a specific pairing, the way White and Red
gives it a white box with red text.
Using the wrong mixin on a slot fails silently. Give a background slot
text-slot and it writes variables no component
reads; nothing on the screen changes.
-
bg-slot($slot, $token): a slot's background paint. -
text-slot($slot, $token): a slot's text paint, dither pattern and clipping included. -
border-level-slot($slot, $level, $dir: h): sets a slot's border to one of the framework border levels. -
border-token-slot($slot, $token, $dir: h): sets a slot's border to a token's fill instead of a level.
Slot values cascade down from the screen, so you can set them again on a component or a state wrapper.
On an unthemed screen, inverse flips its subtree to the opposite scheme.
On a themed screen the subtree keeps the theme's slots; the theme itself restates the slots that should flip, as in the example below.
@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 recolor the raw palette utilities
(bg--*,
text--*,
text-stroke--*), so markup that says
bg--gray-50 follows the theme without edits.
-
utility-remap-grayscale($to-hue, $side): the bulk remap, moving the whole grayscale ladder to a hue;$sidecontrols how. -
utility-remap-border-grayscale($to-hue, $side): the same remap for border lines: their two inks recolor, their patterns keep their shape. -
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): swap one border level for another level's line art, colors and rendering included. The 2-bit borders need this mixin: their four tones are drawn into the line itself, where no token remap can reach them. Restating a level onto itself is not a no-op: it also pins the two ink colors the level's line draws with.
The $side values:
'dark' (default) presses the grays into the
hue's dark steps 10 to 40, keeps black as ink, and sends white to the hue.
'bright' presses them into steps 45 to 75,
sends black to the hue, and keeps white. 'linear'
maps gray steps to hue steps 1:1.
Strokes are the one exception: whichever token maps to the hue itself keeps a visible stroke, taken from the nearest hue step (45 under bright, 40 under dark, 75 under linear), so outlines never dissolve into the canvas.
Black and Yellow remaps to the dark side, and White and Red
remaps to the bright side with one exception, utility-bg("white", "red"),
so white surfaces turn red while white text stays ink. Dark flips the grayscale token by token with
the single-token remaps, and uses
utility-border-level for the 2-bit
borders 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 steps the framework draws borders in: 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 sets a component's border
to a level; utility-border-token recolors a
level itself, and utility-remap-border-grayscale
recolors the two line inks in bulk. See
Border
Border
Draw horizontal and vertical rules on the same shade scale as backgrounds
Draw a horizontal or vertical rule on any element with the border--h and border--v utilities, named on the same 10 to 75 shade scale as backgrounds. On 1-bit displays a step renders as a dither pattern of black and white pixels, so a rule can read as gray. 4-bit and full-color screens draw all 14 steps; everywhere else two neighboring steps share a line.
and
Divider
Divider
Create horizontal or vertical dividers between elements
The Divider element provides a simple, standalone shorthand for horizontal and vertical separators. It draws the same line as the border utilities at level 6, the line the steps 60 and 65 draw.
for how levels
render.
Every border slot and remap changes two things at once: the CSS line, and what
TRMNLPaint.border() and
TRMNLPaint.divider() hand to JavaScript.
Bind a slot to a level and JavaScript gets that level's pattern. Bind it to a token and JavaScript
gets a flat line in the token's stroke color, because only levels have patterns.
The Chart Ramp
chart-series-ramp($tokens, $span: 6) sets
the colors charts pick their series from: list the tokens in order, strongest contrast against the
background first, and series 0 gets the first one. Each entry keeps the token's own rendering, so series
dither or paint solid per device. JavaScript spreads series across the first
$span entries of the list.
A short list is safe. The ramp always has 16 entries; the ones past your last token are cleared
instead of keeping the framework's default grays, and
$span never reaches past your last token.
Charts read the ramp through TRMNLPaint.series();
see
Painting Charts
Painting Charts
Chart series colors for the current device, mode, and theme, with Highcharts adapters
These functions pick the colors for a chart. Ask for series 2 of 5 and you get its paint, correct for the current device, mode, and theme. Adapters then turn each answer into the exact option Highcharts expects.
and
Chart
Chart
Visualize data with charts that adapt to the device and theme
Plugins can draw charts with any JavaScript charting library. The TRMNLCharts helper supplies the framework's colors, so a chart adapts to the device and themes like the rest of the screen.
.
@include theme-slots.chart-series-ramp((
black, yellow-10, yellow-20, yellow-30, yellow-40, yellow-55, yellow-75, yellow
));