Theming
Map every visible region of a plot to the theme() key that styles it.
A Gribouille plot is a stack of named regions: an outer canvas, an inner panel (or grid of panels), a strip band for facets, a legend column, a title block on top, a caption underneath, and axes around the edges. Each region is one entry in the theme() dictionary, set with an element-text, element-line, element-rect, element-blank, or margin value. This page is a map: it shows where each region sits on a real plot, names the theme() key that controls it, and links worked examples for the common overrides.
Anatomy of a plot
The diagram below is a real plot. Each region carries a deliberate fill so you can see where it sits, and a callout names the theme() key that styles it. Compose your own overrides by replacing any of those keys.
Region to theme key reference
The table below names every region the renderer styles and the theme() key that controls it. Each axis family cascades in three steps: per-side (-x-bottom, -x-top, -y-left, -y-right) falls back to per-axis (-x, -y), which falls back to the unprefixed family. Setting axis-text alone styles all four sides at once. The panel grid cascades by weight then axis: per-axis (-x, -y) falls back to the weight (panel-grid-major, panel-grid-minor), which falls back to panel-grid. Minor gridlines default to half the major weight in the same colour, and a blank panel-grid blanks both weights.
| Region | Key(s) | Element type |
|---|---|---|
| Outer plot rectangle. | plot-background. |
element-rect. |
| Breathing room around content (painted rect grows outward to wrap it). | inset on plot-background and legend-background. Ignored on panel-background, strip-background, legend-bar. |
margin. |
| Outer whitespace reservation. | outset on plot-background, panel-background, legend-background, legend-bar. Ignored on strip-background. |
margin. |
| Title, subtitle, caption. | plot-title, plot-subtitle, plot-caption. |
element-text. |
| Drawing area inside a facet. | panel-background. |
element-rect. |
| Gridlines inside the panel, by weight and axis. | panel-grid, panel-grid-major, panel-grid-minor, panel-grid-major-x, panel-grid-major-y, panel-grid-minor-x, panel-grid-minor-y. |
element-line. |
| Facet header band. | strip-background, strip-text. |
element-rect, element-text. |
| Axis line, per side. | axis-line, axis-line-x, axis-line-y, axis-line-x-bottom, axis-line-x-top, axis-line-y-left, axis-line-y-right. |
element-line. |
| Axis ticks, per side. | axis-ticks, axis-ticks-x, axis-ticks-y, axis-ticks-x-bottom, axis-ticks-x-top, axis-ticks-y-left, axis-ticks-y-right. |
element-line. |
| Tick mark length, per side. | tick-length, tick-length-x, tick-length-y, tick-length-x-bottom, tick-length-x-top, tick-length-y-left, tick-length-y-right. |
Typst length. |
| Tick mark labels visible. | tick-labels. |
Boolean. |
| Axis tick labels, per side. | axis-text, axis-text-x, axis-text-y, axis-text-x-bottom, axis-text-x-top, axis-text-y-left, axis-text-y-right. |
element-text. |
| Axis title, per side. | axis-title, axis-title-x, axis-title-y, axis-title-x-bottom, axis-title-x-top, axis-title-y-left, axis-title-y-right. |
element-text. |
| Discrete legend box. | legend-background, legend-title, legend-text. |
element-rect, element-text. |
Continuous colour bar (chrome reuses legend-background / legend-title / legend-text). |
legend-bar, legend-ticks. |
element-rect, element-line. |
| Shared cascade parents (fields inherit down to every descendant surface unset on the child). | text, line, rect. |
Element constructors. |
| Base colour roles (drive geom colour resolution and theme mixing). | ink, paper, accent. |
Colour. |
| Layer aesthetic defaults. | geom. |
element-geom. |
Any key can be hidden with element-blank in place of its normal element. That is how theme-minimal drops the axis line, the panel background, and the tick marks, for example.
Inheritance cascade
Every styled surface walks a parent chain root-to-leaf at render time. The most specific record wins; unset fields inherit from the parent. Two patterns repeat: base records (text, line, rect) feed every descendant surface, and each axis family fans out by axis then by side.
Text sizes accept either an absolute length or a ratio. A ratio such as 80% scales the parent surface size, so setting the base text size rescales every surface that inherits via a ratio (axis titles, tick labels, legend text, and so on). An absolute length such as 12pt pins that surface outright and ignores the cascade.
text, line, or rect cascades to every surface in its column; fields unset on the child inherit from the parent.
Override one region
The lightest possible change is to pass a single record into theme() for the region you care about. The example below lifts the axis-title and axis-text sizes, paints the panel-background cream, and softens the panel-grid. Every other surface keeps its default.
#let df = range(0, 12).map(i => (x: i, y: i * i * 0.1))
#plot(
data: df,
mapping: aes(x: "x", y: "y"),
layers: (
geom-line(stroke: 1.2pt, colour: rgb("#d6604d")),
geom-point(size: 3pt, fill: rgb("#d6604d")),
),
theme: theme(
axis-title: element-text(size: 12pt),
axis-text: element-text(size: 10pt),
panel-background: element-rect(fill: rgb("#f7f0e7")),
panel-grid: element-line(colour: rgb("#d9cfbf")),
),
labels: labels(
title: "theme() overrides",
subtitle: "Larger axis titles, a cream panel fill, and a soft grid",
x: "Step",
y: "y = 0.1 × x²",
),
width: 12cm,
height: 7cm,
)Each line maps directly to one row in the region table: change a single key, the matching region updates, nothing else moves.
Tune the outer canvas
Grow the outer plot rectangle past its content with element-rect’s inset field (inner padding); reserve whitespace around the rectangle with the outset field (outer margin). Each takes a margin with any subset of top, right, bottom, left; sides left at auto add nothing.
#let accent = rgb("#1f77b4")
#let d = range(0, 10).map(i => (x: i, y: i * 0.5))
#let panel(title, theme-arg) = plot(
data: d,
mapping: aes(x: "x", y: "y"),
layers: (
geom-line(stroke: 1pt, colour: accent),
geom-point(size: 2pt, fill: accent),
),
labels: labels(title: title, x: "X", y: "Y"),
theme: theme-arg,
width: 12cm,
height: 6cm,
)
#grid(
columns: 1,
row-gutter: 0.4cm,
panel("Default plot-background", theme-minimal()),
panel(
"plot-background: element-rect(inset: margin(top: 0.6cm, right: 0.6cm, bottom: 0.9cm, left: 1.6cm))",
theme-minimal(plot-background: element-rect(
fill: rgb("#f7f0e7"),
inset: margin(
top: 0.6cm,
right: 0.6cm,
bottom: 0.9cm,
left: 1.6cm,
),
)),
),
)inset grows the painted rectangle outward to wrap its content; only plot-background and legend-background honour it. outset reserves outer whitespace: on panel-background, legend-background, and legend-bar the reservation widens the surrounding cetz chrome slot (shrinking the panel canvas); on plot-background it wraps the rendered block in pad(). strip-background ignores both fields: the facet band has no surrounding slot to grow or reserve into. Facet column and row gutters are a renderer constant, not a theme field. The gap between tick labels and the axis title is controlled by axis-title.margin; gaps around any other text surface use the per-element margin field on its element-text.
Complete vs partial themes
theme() is the full base: every surface listed in the reference table is populated. Use it when you want to start from scratch and define each region yourself.
The library ships eight curated overrides on top of that base. Each one is a thin function that returns a theme with a handful of fields replaced; everything else cascades from theme().
| Function | Effect |
|---|---|
theme-minimal. |
Drops the axis line, the panel background, and the tick marks. The library default. |
theme-bw. |
Black-and-white frame, white panel, light grid. |
theme-classic. |
Axis lines only, no grid, no panel background. |
theme-grey. |
Grey panel background with a white grid. |
theme-light. |
Light frame and grid on a white panel. |
theme-dark. |
Dark frame and grid on a dark panel. |
theme-linedraw. |
Black frame, dark grid, white panel. |
theme-void. |
Everything removable removed; useful for inset thumbnails. |
The theme-sub-* helpers go one level finer: they bundle the keys that move together for a single region. For example, theme-sub-axis accepts line, ticks, text, title, and rewrites the four corresponding theme() keys for you. The full set is theme-sub-axis, theme-sub-axis-x, theme-sub-axis-y, theme-sub-axis-bottom, theme-sub-axis-top, theme-sub-axis-left, theme-sub-axis-right, theme-sub-legend, theme-sub-panel, theme-sub-plot, and theme-sub-strip.
Finally, theme-set installs a theme as the document-wide default so subsequent plot() calls pick it up without an explicit theme: argument.
Where to go next
- Browse the themes gallery for side-by-side renders of every built-in theme, alongside the other theme examples.
- See
theme-sub-*in action for compact ways to retouch one region at a time. - The full themes reference lists every element constructor and every cascade rule.