CSS Variables
Every framework CSS variable is either public contract or private implementation. This page states the contract: which families are public, which are internal, and how the Paint API reads them, themes re-point them, and the Sass source generates them.
Who reads, who writes
The public --* variables are where the
framework's API surfaces meet. Each surface plays one role and never crosses into another.
- Sass generates them. The SCSS source emits every variable with its per-device values, and a custom build can extend the set. See Sass API Sass API The framework SCSS source: architecture, cascade layers, and what a custom stack can build from it The Sass API is the framework's SCSS source, open since 3.2. A custom stack serves either an official released build or its own build compiled from this source; these pages document the build-your-own path. The TRMNL Platform always serves official builds. .
- Themes re-point them. A theme sets token references through the slot mixins and never writes paint values directly. See Themes Themes Opt-in stylesheets that re-theme screens while preserving device-capability rendering Themes are standalone stylesheets that re-point semantic channels, component slots, and utility tokens at different palette tokens. A themed screen still renders through its device mode: dither patterns on 1-bit, palette images on limited color, solids on full color. and Authoring Themes .
- Paint reads them. TRMNLPaint resolves the live cascade into canonical Fill, BorderFill, and TypeSpec objects for JavaScript. See Paint API Paint API TRMNLPaint: read the live CSS cascade from JavaScript to resolve framework colors and tile patterns TRMNLPaint is the framework's public JavaScript paint API. It reads the live CSS cascade (bit depth, dark mode, theme, limited palette, and tiles all resolved) and hands back a canonical Fill, so token mappings are never duplicated in JavaScript. Charts are just one consumer; any plugin can resolve framework colors from JS for any purpose. .
The palette behind the variables is defined on
Colors
Colors
Complete palette definition: grayscale, chromatic hues, and semantic roles
The Colors system defines the complete palette for the framework: grayscale, chromatic hues, and semantic roles (primary, success, error, warning). Use these tokens with bg--, text--, and other utilities. See Background and Text Color for usage examples.
. Every variable
with its per-mode values is listed on
Tokens
Tokens
Complete CSS variable reference with root defaults, density, and bit-depth overrides
The Tokens reference lists every Framework CSS variable from _variables_root.scss and display overrides in _variables_overrides.scss. Use it to understand defaults, 2-bit visual/layout behavior, high-density typography, and 4-bit-and-up scaling.
.
Public variables
A variable is public unless its name marks it as internal, and a release keeps every public name in
every published bundle. Read public variables with
var() in custom CSS or
cssVar() in JavaScript, and reference them
from theme slots.
- Palette:
--black,--white, the--gray-*ladder, and one ladder per hue:--red-*,--orange-*,--yellow-*,--lime-*,--green-*,--cyan-*,--blue-*,--violet-*,--purple-*,--pink-*. - Semantic roles: the
--color-*family, which holds the roles (--color-primary,--color-success,--color-error,--color-warning) and the palette-mode ids, not hues. - Geometry and scale:
--screen-*,--gap-*,--rounded-*, and the resolved--ui-scale,--content-scale, and--text-ui-scalefactors. - Component tokens: the families components read, from
--title-bar-*to--progress-*, all listed on Tokens Tokens Complete CSS variable reference with root defaults, density, and bit-depth overrides The Tokens reference lists every Framework CSS variable from_variables_root.scssand display overrides in_variables_overrides.scss. Use it to understand defaults, 2-bit visual/layout behavior, high-density typography, and 4-bit-and-up scaling. .
The --framework-* channels are public too. They
get their own section below because the theme layer and the runtime write them.
/* Custom plugin CSS: reference public variables freely. */
.stat-card {
padding: var(--gap);
border-radius: var(--rounded);
}
// JavaScript: read the same contract from the live cascade.
var gap = TRMNLPaint.cssVar("--gap", { el: "my-chart" });
Framework channels and slots
The --framework-* families carry resolved paint
between the theme layer, the components, and the runtime. They are public names: the minifier renames only
the internal families below, so a theme, a plugin stylesheet, or
cssVar() can read them in any build.
- Semantic channels:
--framework-semantic-{channel}-*for canvas, surface, backdrop, fill-strong, fill-muted, fill-soft, text-primary, text-secondary, text-inverse, stroke-contrast, border-strong, border-muted, and icon. A channel carries its whole paint: backgrounds have-bg-colorand-bg-image, text adds-text-underand-text-clipto its color and image, and borders carry-border-color,-border-image, and-border-size. - Role aliases: one flat color per role, resolved from the matching channel:
--framework-canvas-bg,--framework-surface-bg,--framework-backdrop-bg,--framework-text-primary,--framework-text-secondary,--framework-text-inverse,--framework-border-strong,--framework-border-muted,--framework-outline-strong,--framework-stroke-contrast,--framework-fill-strong,--framework-fill-muted,--framework-fill-soft. They drop the dither image, so use them only where a single color is what you want. - Component slots:
--framework-slot-{slot}-*, one group per component surface (title bar, screen backdrop, item meta, progress, table, label). A slot repaints one surface without moving a whole channel. See Theme Slots Theme Slots Every themable surface: semantic channels, component slots, utility remaps, border lines, and the chart ramp 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. . - Chart ramp:
--framework-chart-series-{i}-colorand--framework-chart-series-{i}-imagefor series indexes 0 to 15, plus--framework-chart-series-spanfor the legible front of the ramp. See Painting Charts Painting Charts Chart series colors from the framework ramp, with Highcharts adapters The chart resolvers pick evenly spaced series colors from the framework chart ramp, resolved through the live cascade. Adapters convert the resulting Fills into Highcharts color options. . - Border render contract:
--framework-border-render-*(width,height,view-box,stroke,path-1,path-2,color-1,color-2): the border program the border pipeline declares and the Paint API copies into SVG. See Painting Borders Painting Borders Read border rails as BorderFill objects for custom rails and Highcharts axes The border resolvers read the framework border rails as BorderFill objects. Apply them to custom rails, or convert them for Highcharts axes and grid lines. . - Icon source:
--framework-icon-srcholds the URL animage--adaptiveelement is masked with. The runtime writes it as an inline style, and markup can set it directly. See Image Image Optimize images using dithering techniques for 1-bit rendering 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. .
Themes write these through the slot mixins, where one call fills a whole channel or slot. Setting a single
name by hand leaves the rest of its group behind, so plugin markup sets only
--framework-icon-src.
Internal variables
Six name families are implementation details. The minified bundle
(plugins.min.css, the file production serves)
renames them to --_tn* names. Do not read or
set them; they can change or disappear in any release.
--_*: module-private helpers scoped to one component's rules.--framework-internal-*: plumbing that carries resolved values between framework layers.--tile-*: the generated dither tile assets.--bline-{n}: deduplicated border line gradients the border pipeline references.--border-*: the border pipeline, except the theme-contract names below.--tn-*: engine plumbing, except--tn-text-stroke-color,--tn-text-stroke-widthand--tn-text-stroke-radius, which the runtime reads.
The development build and the readable plugins.css
keep the source names, so you will see them in devtools. Treat them as off-limits anyway.
Framework-owned paint variables
The --bg-* and
--text-* families keep their names in every
build, but the screen-mode engine owns them. They encode device-capability rendering: dither patterns on
1-bit, palette images on limited color, solid colors on full color.
Three border families survive the rename because the theme contract preserves them: the numbered slots
--border-1-h-* through
--border-7-v-*, the
--border-token-* names a shipped theme
references, and --border-line-dark /
--border-line-light. Everything else under
--border-*, including the whole
--border-step-* rail, is renamed in released
bundles.
Never set them from a plugin or a theme; the theme linter rejects any theme that tries. To consume the resolved paint from JavaScript, go through Paint API Paint API TRMNLPaint: read the live CSS cascade from JavaScript to resolve framework colors and tile patterns TRMNLPaint is the framework's public JavaScript paint API. It reads the live CSS cascade (bit depth, dark mode, theme, limited palette, and tiles all resolved) and hands back a canonical Fill, so token mappings are never duplicated in JavaScript. Charts are just one consumer; any plugin can resolve framework colors from JS for any purpose. instead of reading them raw.