Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Theme roles

The tuile theme system resolves a small base palette into semantic colour roles for every surface, text, border and chrome element. Every role on Theme is a plain Rgb value you can read directly; most are derived by CIE-Lab lightness transformations or auto-contrast blending.

Base palette

Set directly by ThemeSpec:

RoleFieldDerived fromUsed for
Primary colourprimaryThemeSpec.primaryBorders, buttons, accents (Primary variant)
Secondary coloursecondaryThemeSpec.secondary or primarySecondary variant buttons, links
Warning colourwarningThemeSpec.warning or primaryWarning variant elements
Error colourerrorThemeSpec.error or secondaryError variant elements
Success coloursuccessThemeSpec.success or secondarySuccess variant elements
Accent colouraccentThemeSpec.accent or primaryAccent variant highlights
BackgroundbackgroundThemeSpec.background or #121212 (dark) / #efefef (light)Page background
ForegroundforegroundThemeSpec.foreground or background.inverse()Maximum contrast text reference

Surface roles

RoleFieldDerived fromUsed for
SurfacesurfaceThemeSpec.surface or #1e1e1e (dark) / #f5f5f5 (light)Default widget background
Panelpanelsurface.blend(primary, 0.1) + 4% contrast tint (dark)Containers, panels, cards
Boostboostsurface.blend(foreground, 0.04)Nested containers (Textual $boost)

Text roles

All text roles are derived for readability over the background. The auto N% notation means background.text_on(N), which blends the best-contrast text (white or black) at the given alpha.

RoleFieldDerived fromUsed for
Default texttextbackground.text_on(0.87)Primary body text (auto 87%)
Muted texttext_mutedbackground.text_on(0.60)Secondary labels, help text (auto 60%)
Disabled texttext_disabledbackground.text_on(0.38)Disabled controls (auto 38%)
Primary texttext_primaryforeground.blend(primary, 0.66)Tinted text for Primary variant
Secondary texttext_secondaryforeground.blend(secondary, 0.66)Tinted text for Secondary variant
Accent texttext_accentforeground.blend(accent, 0.66)Tinted text for Accent variant
Success texttext_successforeground.blend(success, 0.66)Tinted text for Success variant
Warning texttext_warningforeground.blend(warning, 0.66)Tinted text for Warning variant
Error texttext_errorforeground.blend(error, 0.66)Tinted text for Error variant

Border and cursor roles

RoleFieldDerived fromUsed for
Border (focused)borderprimaryFocused widget borders
Border (blurred)border_blurredsurface.darken(0.025)Unfocused borders (CIE-Lab −2.5% L*)
Cursor backgroundcursor_bgprimaryText cursor fill colour
Cursor foregroundcursor_fgprimary.text_on(0.9)Text under cursor (auto 90% on cursor_bg)
Cursor blurredcursor_blurred_bgsurface.blend(primary, 0.3)Unfocused cursor (30% primary over surface)

Interaction roles

RoleFieldDerived fromUsed for
Hover backgroundhover_bgsurface.blend(foreground, 0.08)Button/item hover state
Selection backgroundselection_bgsurface.blend(primary, 0.5)Selected text, list items
Link colourlinksecondary.blend(foreground, 0.2)Hyperlinks

Scrollbar roles

RoleFieldDerived fromUsed for
Scrollbar thumbscrollbarbackground.darken(0.15).blend(primary, 0.4)Scrollbar handle (40% primary on darkened bg)
Scrollbar hoverscrollbar_hoverbackground.darken(0.15).blend(primary, 0.6)Hovered scrollbar thumb (60% primary)
Scrollbar trackscrollbar_bgbackground.darken(0.15)Scrollbar track (CIE-Lab −15% L*)

Special widget roles

RoleFieldDerived fromUsed for
Toast backgroundtoast_bgpanel.lighten(0.15)Toast/notification background (CIE-Lab +15% L*)
Footer backgroundfooter_bgpanelKeyFooter background
Footer keyfooter_keyaccentKeyFooter key binding colour
Footer descriptionfooter_descpanel.text_on(0.87)KeyFooter description text (auto 87% on panel)
Markdown code backgroundmarkdown_code_bgsurface.blend(foreground, 0.06)Inline code blocks in Markdown

Helper methods

Theme::shade

pub fn shade(c: Rgb, n: i32) -> Rgb

Textual’s $color-lighten-N / $color-darken-N: shifts CIE-Lab L* by 15% per step. Positive n lightens, negative darkens. Matches Textual’s lightness transformations (e.g. shade(primary, 1) = +15% L*, shade(primary, -2) = −30% L*).

Rgb::text_on

pub fn text_on(self, alpha: f32) -> Rgb

Textual’s auto N%: blends the best-contrast text (white or black, chosen by self.contrast_text()) over this colour at the given alpha (0.0 = transparent, 1.0 = fully opaque). Use this to generate readable text over any background: bg.text_on(0.87) gives primary readable text, bg.text_on(0.60) gives muted secondary text.

Choosing the right role

What you are drawingRole to use
Text over the page backgroundtext, text_muted or text_disabled
Text over a widget surface or panelsurface.text_on(0.87) or panel.text_on(0.87)
Text inside a coloured button or badgevariant_colour.text_on(0.9)
Text tinted to carry meaningtext_primary, text_success, text_error and the rest of that set
A borderborder when focused, border_blurred when not
A hover stateblend hover_bg over the widget surface
A lighter or darker step of any colourTheme::shade(colour, steps), which matches Textual’s 15% L* step, rather than raw lighten()