Skip to main content
The engine stacks the title, legend, axes, plot and footer. gap is the space between items inside a chrome target (pills in a legend, cards in a headline). margin is the air around a chrome target that occupies a layout slot. padding is the frame. Legend position lives on config.legend. Two neighboring keys also change how much room the chart needs, so they are covered here too: panel.overflow and style.graph({ textScale }).

Padding

number | { top?: number; right?: number; bottom?: number; left?: number }
default:"24"
Outer padding in pixels, authored on style.graph. A number applies to all four sides; an object ({ top?, right?, bottom?, left? }) sets sides one by one. Omitted edges keep the built-in 24.
A side left out of the object keeps the 24px default, so this trims the left edge and opens up the top while the other two stay put:
An explicit 0 removes a side’s padding. Padding is in pixels and does not follow textScale.

Margin

Air around a chrome target that occupies a layout slot lives on that target’s margin. Values are pixels and do not follow textScale. A number sets every side. An object sets single edges; omitted sides stay absent, so they do not overwrite earlier entries. 0 closes a side.
When two boxes meet, the larger of the two facing margins is used, not their sum. A box the chart does not draw contributes none. A margin that faces the frame adds to style.graph({ padding }). style.legend, style.axisLabel and style.tickLabel take .top / .right / .bottom / .left as well as .x / .y. A bare call covers every instance; a later match decides. The built-in entries:
A tight preset that wants less space below the title:
style.header({ margin: 4 }) would also add 4px above the title, on top of the padding. legend.margin does nothing when no legend is drawn. Direct labels sit on the plot and read style.directLabel.

Panel overflow

The panel is the plot area. Data labels and difference arrows can reach past its edge. panel.overflow says what the engine does about it, per content type and per direction:
{ x: PanelOverflowStrategy; y: PanelOverflowStrategy }
default:"{ x: 'inside', y: 'inside' }"
Strategy for data labels that reach past the panel edge.
{ x: PanelOverflowStrategy; y: PanelOverflowStrategy }
default:"{ x: 'outside', y: 'outside' }"
Strategy for difference-arrow annotations.
Each direction takes one of three strategies:
  • 'outside' — the element lands outside the panel and the panel shrinks to make room.
  • 'inside' — the element stays inside the panel and the content within it shrinks instead.
  • 'none' — nothing moves; the element may overlap whatever is beside it.
x covers the left and right edges, y the top and bottom. Only cartesian graphs make room; a polar graph ignores panel.overflow.

Text scale

number
default:"1"
A multiplier on every text size in the chart. 1.2 makes titles, axis labels, tick labels and data labels 20% larger. Authored on style.graph.
It changes measured text, and so the size of every region the engine arranges. gap, offset, margin, padding and stroke widths do not scale.
Renderer contract: a custom renderer must apply textScale both when it measures text and when it renders it. The engine assumes the measured sizes already include the multiplier, so applying it to only one of the two breaks the layout. Slot measure callbacks receive it on SlotMeasureContext.
  • Styling — the graph background, frame border, corner radius, textScale, outer padding and chrome margin
  • Legend — legend position stays on config.legend