Skip to content

Theming & Styling

D3plus assigns colors, fonts, and label styles automatically, but every visual detail is configurable.

theme sets every chrome color at once: the background, the title, axes, gridlines, legend, timeline, tooltip, table view, and the overlays drawn over the chart (minimap, search count, attribution).

<BarChart config={{data, groupBy: "region", x: "quarter", y: "revenue", theme: "dark"}} />
  • "auto" (the default) paints no background and follows the page behind the chart: its text contrasts with the page, its tooltip, table view, and overlays turn dark on a dark page, and it redraws when the page flips between light and dark (a theme class or style on <html> or <body>, or the system theme under color-scheme: light dark).
  • "light" and "dark" paint the theme’s background behind the chart, so it reads the same on any page and in a saved PNG, JPG, SVG, or server render.
  • An object sets your own tokens on top of the preset its base names ("light" or "dark"; without one, a dark background picks the dark preset):
<BarChart config={{
data, groupBy: "region", x: "quarter", y: "revenue",
theme: {
base: "dark",
background: "#14213d",
accent: "#fca311",
tooltip: {background: "#22345c", border: "#fca311"}
}
}} />
Token Colors
background Behind the chart (painted for every theme but "auto")
text Title, subtitle, total, legend, and timeline labels
textMuted The table view’s empty state, the crosshair, and axis hover marks
axis Axis lines, ticks, and tick labels
gridline Gridlines
accent The timeline’s selection and handle
hidden Legend items hidden by a click (hiddenColor)
link Links between nodes (Network, ArcDiagram, Rings, Sankey; the dark preset draws Sankey’s wide bands in a dimmer gray unless you set this), and Alluvial’s nodes outside its colorBy column
tooltip {background, text, border, shadow, divider}
overlay {background, text, border} for the minimap, search count, and attribution
table {background, text, header, border, rule} for the table view
colorScale {max, mid, min, missing} for color scales (see Color scales on a dark theme)

Colors you set elsewhere still win over the theme: an explicit titleConfig.fontColor, tooltipConfig.background, minimapStyle, and so on. The chart’s categorical data colors don’t change with the theme (color scales do; see below), and labels inside shapes already contrast with each shape’s fill.

By default each group gets a distinct color from the @d3plus/color palette. Override per datum with the color accessor or via shapeConfig.fill:

<BarChart config={{
data, groupBy: "region", x: "quarter", y: "revenue",
shapeConfig: {
fill: d => d.region === "North" ? "#cc0000" : "#0066cc"
}
}} />

The default palette is designed for colorblind safety — its slots stay distinct under protanopia and deuteranopia and sit within a controlled lightness/chroma band. To color an ordered categorical field with a single-hue light→dark ramp instead of nominal hues, set colorOrdinal: true. See Guides → Color for the full color system, including how to validate your own palette.

To encode a continuous measure as color, set colorScale to a numeric accessor and tune it with colorScaleConfig. The scale option chooses the binning strategy:

<Geomap config={{
data, groupBy: "id", colorScale: "value",
colorScaleConfig: {scale: "jenks"}, // "linear" | "jenks" | "quantile" | "buckets"
colorScalePosition: "right" // "auto" | "top" | "bottom" | "left" | "right" | false
}} />

By default a continuous scale steps through a single blue hue (darker = larger) and a diverging scale runs blue↔gray↔red; override either by passing a color array to colorScaleConfig.

A pale→dark ramp reads backwards on a dark background: the smallest values become the brightest marks. So on a dark theme ("dark", or "auto" on a dark page) every color scale turns around. A sequential scale runs from a dim, low-chroma tint just above the background up to a bright blue, so low values recede and high values stand out. A diverging scale meets at a dark neutral instead of near-white, with bright red and blue poles of equal lightness. The ramps are stepped evenly in OKLab and stay in one hue, so they still read in grayscale and under color-vision deficiency. The legend’s swatches or gradient, the hover mark, and colorOrdinal ramps follow suit. Light charts keep their pale→dark ramps.

The theme’s colorScale tokens set these colors:

Token Light preset Dark preset Colors
max #1c7ed6 #4dabf7 The high end of single-hue ramps and the positive pole of diverging scales
mid #f8f9fa #343a40 The midpoint of diverging scales
min #c92a2a #ff6b6b The negative pole of diverging scales, and the hue of all-negative ramps
missing unset unset Marks without a value: Geomap regions and Calendar days (unset, each chart derives a quiet neutral from the background)

The light preset’s values are the colorDefaults (sequential, light, and off), so a chart’s own colorDefaults still apply on light. A custom theme can set any of them:

<Geomap config={{
data, groupBy: "id", colorScale: "value",
theme: {base: "dark", colorScale: {max: "#ffd43b", missing: "#2b2d31"}}
}} />

Colors set on the chart still win: colorScaleConfig.colorMax, colorMid, and colorMin replace the matching token (on a dark theme the ramp still runs dim→bright toward your colorMax), and a color array is used exactly as given. @d3plus/color exports the dark ramp as colorRampDark(base, n, {background}), next to colorRamp.

Texture fills give a second, color-independent visual channel — useful for colorblind viewers or grayscale printing. Apply them through shapeConfig:

<BarChart config={{
data, groupBy: "region", x: "quarter", y: "revenue",
shapeConfig: {
texture: d => d.region === "North" ? {} : false,
textureDefault: "lines" // lines | circles | crosses | waves | woven | …
}
}} />

See the Accessibility page for the full list of texture types.

Set a global typeface with fontFamily, and style data labels through the per-shape labelConfig:

<Treemap config={{
data, groupBy: "id", sum: "value",
fontFamily: "Inter",
shapeConfig: {
labelConfig: {fontSize: 14, fontColor: "#222"}
}
}} />

Label text color is chosen automatically for contrast against each shape’s fill (see colorContrast on the Accessibility page).

Pass a locale to translate built-in UI text and format numbers/dates for that region. @d3plus/locales ships dictionaries for several languages, including right-to-left scripts:

<BarChart config={{data, groupBy: "region", x: "quarter", y: "revenue", locale: "ar-SA"}} />

Add framing text around any chart with title, subtitle, and total:

<Pie config={{
data, groupBy: "id", value: "value",
title: "Sales by Product",
subtitle: "Fiscal Year 2024",
total: true
}} />