Skip to content

Themes

A theme is the visual identity of a board: its typography, its canvas, its palette, and how every axis, rule, and table row is painted. You pick one with a single line at the top of the board file, and every chart on the board inherits it.

title: "Sales Dashboard"
theme: neon

rows:
  - revenue_chart

Five themes ship with dbt Charts. Everything below the theme line stays the same, so switching one is a one-word edit.


The five built-in themes

The same board, rendered five times. Only the theme: line differs.

Serif headings on white. The default, and the one to start from.

Northwind Coffee, Q3 $1,284,500 Revenue 8,420 Orders JulAugSep$0$100,000$200,000Revenue by ChannelWholesaleRetailSubscription Data as of 13:34 UTC on 14 Sep 2026 made withdbt Charts

Clarity's typography on a warm cream canvas, with matching gridlines and rules.

Northwind Coffee, Q3 $1,284,500 Revenue 8,420 Orders JulAugSep$0$100,000$200,000Revenue by ChannelWholesaleRetailSubscription Data as of 13:34 UTC on 14 Sep 2026 made withdbt Charts

A crafted sans and a saturated palette. Loud, systematic, high contrast.

Northwind Coffee, Q3 $1,284,500 Revenue 8,420 Orders JulAugSep$0$100,000$200,000Revenue by ChannelWholesaleRetailSubscription Data as of 13:34 UTC on 14 Sep 2026 made withdbt Charts

The dark theme. Near-black canvas, bright marks, inverted scaffold.

Northwind Coffee, Q3 $1,284,500 Revenue 8,420 Orders JulAugSep$0$100,000$200,000Revenue by ChannelWholesaleRetailSubscription Data as of 13:34 UTC on 14 Sep 2026 made withdbt Charts

Bare chrome: plain sans, a boxed plot frame, black rules. It is the structural root every other built-in theme extends, and it carries the same series palette as vivid; what it strips is the scaffold, not the color.

Northwind Coffee, Q3 $1,284,500 Revenue 8,420 Orders JulAugSep$0$20,000$40,000$60,000$80,000$100,000$120,000$140,000$160,000$180,000$200,000$220,000$240,000$260,000Revenue by ChannelWholesaleRetailSubscription Data as of 13:34 UTC on 14 Sep 2026 made withdbt Charts
Theme Voice Canvas
clarity Serif typography, gray scaffold. The default. White
paper Clarity on a warm cream background. Cream
vivid Crafted sans, loud and systematic. White
neon Crafted sans, dark. #161616
stark Bare chrome, structural. Every other theme extends it. White

Those five names are the entire set. A typo, or an invented combination like clarity-paper, is rejected at compile time rather than quietly falling back to the default:

title: "Quarterly Report"
theme: clarity-paper

rows:
  - revenue_chart
ERR-UNKNOWN-THEME  Unknown theme 'clarity-paper'. Available built-in themes:
clarity, neon, paper, stark, vivid.
Hint: Did you mean 'clarity'?

Saved inside a project, the same board reports ERR-EXTENDS-UNRESOLVED instead: there, extends: can also name a board at the project root, so the compiler tried that too and offers it as a fix.


What a theme owns

dbt Charts splits visual decisions three ways, and the split is what keeps themes swappable:

  • Theme answers how the scaffold is painted: fonts, colors, surfaces, palette choices, stroke and fill, mark widths.
  • Style preset answers what scaffold exists and where it sits: which side an axis is on, whether grids and domains are drawn, where the legend goes, how a title is anchored.
  • Chart answers what this chart means: its query, its type, and the columns bound to each channel.

A fourth bucket is deliberately empty: some properties, compatibility surfaces such as series, are kept out of reusable preset and theme ownership entirely.

At render time the merge order is base vega.config, then the selected theme, so a theme wins over a project-wide Vega-Lite config default.

So a theme is the default owner of properties like style.background, style.charts.color.gradient.palette, the visual mark.* leaves (color, fill, stroke, opacity, stroke width), and the spark and spark_bar paint surfaces. Concretely, changing a theme restyles:

  • the board background and every card surface
  • chart marks: bars, lines, areas, points
  • axis grid lines, labels, and titles
  • table headers, borders, and row stripes
  • variable inputs: backgrounds, borders, labels
  • title and body text color

A theme should not be the home for scaffolding defaults. If you find yourself deciding where an axis sits or whether grids are shown, that belongs in a style preset instead. For the full board-level style: inventory, see Styling.


Custom themes

A custom theme is not a new file format and not a fork of a built-in. It is an ordinary board file that extends: a theme and overrides only the keys you name. Everything you do not name is inherited.

Extending is a deep merge

extends: deep-merges the boards you list, in order, with later entries winning. Because the merge is deep, naming style.charts.color.categorical.palette replaces exactly that leaf; the rest of the theme's chart styling is untouched.

Here is clarity wearing one company's brand: a canvas, an accent, and a palette. Everything else, the serif headings, the axis treatment, the type scale, the spacing, is still clarity:

title: "Northwind Coffee, Q3"

extends: clarity

style:
  background: "#fbf7f0"
  accent: "#a1421f"
  charts:
    color:
      categorical:
        palette: category-6-tonal-orange
        single_series_palette: category-6-tonal-orange

queries:
  monthly:
    columns: [month, channel, revenue]
    values:
      - [Jul, Wholesale, 214000]
      - [Aug, Wholesale, 231500]
      - [Sep, Wholesale, 248900]
      - [Jul, Retail, 138400]
      - [Aug, Retail, 151200]
      - [Sep, Retail, 166300]
      - [Jul, Subscription, 41800]
      - [Aug, Subscription, 49600]
      - [Sep, Subscription, 58800]

charts:
  trend:
    query: monthly
    type: line
    title: Revenue by channel
    x: month
    y: revenue
    color: channel
    style:
      axis_y:
        labels:
          format: currency_whole

rows:
  - trend
Northwind Coffee, Q3 JulAugSep$0$100,000$200,000Revenue by ChannelWholesaleRetailSubscription Data as of 13:34 UTC on 14 Sep 2026 made withdbt Charts

One thing worth noticing: a theme's surfaces are chosen together. Move the canvas to a warm cream and the cool-gray table stripe inherited from clarity will read as a cast against it, so name that too:

style:
  charts:
    table:
      row:
        stripe:
          color: "#f4ece0"

Lifting it into a shared file

Once more than one board wants that look, move the style: block into its own board file under charts/. Prefix the filename with an underscore to mark it as a non-listable building block: it will not appear in board listings, but other boards can extend it.

# charts/_northwind-brand.yml
extends: clarity

style:
  background: "#fbf7f0"
  accent: "#a1421f"
  charts:
    color:
      categorical:
        palette: category-6-tonal-orange
        single_series_palette: category-6-tonal-orange

rows: []

Then point boards at it. For the whole project at once, put it in charts/meta.yml, which cascades to every board beneath it:

# charts/meta.yml
extends: ./_northwind-brand.yml

Or on one board:

# charts/my-dashboard.yaml
extends: ./_northwind-brand.yml

The layer already names its base theme (extends: clarity above), so a board never lists the theme beside it. A board's own extends: merges over the project's, key by key, which is how a dark variant becomes one line on the boards that want it. In dbt Charts Cloud, the Design panel's Theme select and Project Settings offer these layers by title, beside the built-ins.

Two rules that bite

Reach for a path ref. An entry with no / and no .yaml/.yml extension is read as a built-in theme name first, and otherwise as a board at your project root, not under charts/. So extends: _northwind-brand will not find charts/_northwind-brand.yml; extends: ./_northwind-brand.yml will.

A list composes, and later entries win. extends: also takes a list, for stacking one layer on another: a layout template under a brand layer, say. Later entries win the style merge, and the last recognized theme name anywhere in the chain sets the palette and paint defaults. A theme name has no place in that list when a layer already extends it.

The Playground gallery's composition/_report-base.yml is a template any board can extends: to inherit its theme and card spacing.

Overriding one board, or one chart

You do not need a custom theme to change one thing once. A board's own style: block cascades on top of whatever theme is active, and a chart's style: cascades on top of the board's:

theme: paper

style:
  background: "#ffffff"

charts:
  revenue_chart:
    query: monthly
    type: line
    x: month
    y: revenue
    style:
      color:
        static: "#a1421f"

Chart styles are sparse overlays: an omitted field inherits the nearest theme or board value, and an explicit null clears a nullable one.


Where to go next

  • Styling for the full style: inventory, format aliases, text and border styling, and per-chart overrides.
  • Palettes for the shipped palette catalog with visible swatches, and how categorical, sequential, and diverging families differ.
  • Tonal Foundations for the design reasoning behind the neutral scaffold colors.