Deep Dive
Power BI Theme JSON: A Practical Guide to Schema 2.159 (2026)
TL;DR
A Power BI theme is a JSON file where only name is required. Add dataColors for series, good/neutral/bad for status, structural colours (foreground, background, tableAccent and friends), four primary textClasses (callout, title, header, label) and visualStyles for per-visual defaults. Validate it against reportThemeSchema-2.159.json (October 2026) before importing. Import from the Design ribbon > Import theme. A theme can also carry the page background as a base64 image.
Theme JSON is the most effective lever you have on Power BI report design: one file sets colours, fonts and per-visual defaults for every page, and it travels between reports. It's also strict. Power BI validates the file against a published JSON schema and rejects anything it doesn't recognise. This guide covers the parts that matter, in the order you'd write them, with JSON you can copy.
Start with the smallest valid theme
The only required property is name. Everything else is optional and layers on top of Power BI's base theme, so you add only what you want to change.
A useful starter adds a colour palette and the three structural colours that most visibly change a report: background, foreground and tableAccent. Microsoft's own samples (the St Patrick's Day and Valentine's Day themes on Learn) are exactly this shape.
Point the file at the schema while you edit. Microsoft publishes the schema in the microsoft/powerbi-desktop-samples repository on GitHub, one file per monthly Desktop release. The newest at the time of writing is reportThemeSchema-2.159.json, for the October 2026 release (exploration version 5.78). Download it next to your theme and add a $schema property; VS Code then autocompletes property names and underlines invalid ones. Power BI Desktop uses the same schema to validate imports, so a file that validates in VS Code imports cleanly.
brand-theme.json
{
"$schema": "reportThemeSchema-2.159.json",
"name": "Northwind Brand",
"dataColors": ["#2563EB", "#0EA5E9", "#F59E0B", "#10B981", "#8B5CF6", "#EF4444", "#64748B", "#14B8A6"],
"background": "#FFFFFF",
"foreground": "#1F2937",
"tableAccent": "#2563EB",
"good": "#15803D",
"neutral": "#B45309",
"bad": "#B91C1C"
}Theme colours: dataColors, sentiment and gradients
dataColors is the series palette. Power BI assigns colours in order: the first series gets the first colour, the second gets the second, and so on. The list can be any length; when Power BI runs out, it generates extra colours by shifting hue and saturation. Eight well-separated colours is a practical number.
Order matters more than people expect. Colour follows position in each visual, not the category value, so "North" can be blue in one chart and orange in another if it appears second there. Put your most important brand colour first and choose the second colour to contrast clearly with it.
good, neutral and bad are the status colours used by the KPI visual and waterfall charts. maximum, center, minimum and null set the defaults in the conditional formatting gradient dialog.
These names are also usable from DAX. With Field value conditional formatting, a measure can return the theme colour name instead of a hex code, and the visual uses the current theme's colour. Switch themes and the formatting follows.
Status Color.dax
Status Color =
VAR Score = [Status Score]
RETURN
SWITCH (
TRUE (),
Score >= 80, "good",
Score >= 50, "neutral",
"bad"
)Structural colours: the six classes that style everything else
Structural colours set the non-data parts of the report: gridlines, labels, table text, slicer chrome, button fills. Learn documents six classes plus tableAccent, each with an older alias:
firstLevelElements (alias foreground): primary text such as card data labels, table and matrix values, textbox default colour, KPI text, slicer header text and filter pane text.
secondLevelElements (alias foregroundNeutralSecondary): secondary text such as axis labels, legend labels, table headers and button text.
thirdLevelElements (alias backgroundLight): gridlines, table grid, shape fill and the gauge arc background.
fourthLevelElements (alias foregroundNeutralTertiary): dimmed legend items and card category labels.
background: label backgrounds inside data points, slicer dropdowns, button fill, the filter pane and modern tooltip backgrounds.
secondaryBackground (alias backgroundNeutral): table and matrix grid outlines and disabled button fills.
For a dark theme, set all of these, not just background and foreground. If you only flip the page colour, data label backgrounds, gridlines and secondary text keep their light-theme values and become unreadable. Microsoft's tip is specific: set firstLevelElements to your primary text colour, secondLevelElements to the lighter text colour, and choose a background that contrasts with both.
Since the 2.152 schema (March 2026), colour fills inside visualStyles can also reference these names, for example { "solid": { "color": "foreground" } }, so you no longer repeat hex codes throughout the file. Eight-digit hex values with an alpha channel, such as #0000FF7F, are accepted too.
textClasses: four primary classes control all text
Learn documents 12 text classes (the 2.159 schema lists a couple more, such as dataTitle). Four are primary, and the others derive from them automatically, so in practice you set four:
callout: card data labels and KPI indicators. Default DIN, 45 pt, #252423.
title: axis titles, multi-row card titles and slicer headers. Default DIN, 12 pt. Its secondary class largeTitle (14 pt) formats visual titles.
header: key influencers headers. Default Segoe UI Semibold, 12 pt.
label: table and matrix values and headers. Default Segoe UI, 10 pt, #252423. Its secondaries include lightLabel (legend text, button text, category axis labels), boldLabel (totals), smallLightLabel (data labels and value axis labels) and largeLightLabel (card category labels).
Each class takes fontFace, fontSize and color, and bold where it applies. The secondary classes inherit size steps and lighter colours from the primary, and the light variants take their colour from the structural colours above, which is another reason to set those in a dark theme.
Pick fonts your viewers have. A font that isn't installed on the viewer's machine or supported by the service falls back to a default, and the layout shifts. Segoe UI, DIN, Arial and Calibri are safe choices.
textClasses excerpt
"textClasses": {
"callout": { "fontFace": "Segoe UI Semibold", "fontSize": 28, "color": "#111827" },
"title": { "fontFace": "Segoe UI Semibold", "fontSize": 12, "color": "#111827" },
"header": { "fontFace": "Segoe UI Semibold", "fontSize": 12, "color": "#111827" },
"label": { "fontFace": "Segoe UI", "fontSize": 10, "color": "#374151" }
}visualStyles: defaults and presets per visual type
visualStyles is where themes become powerful, and where most import errors happen. The structure is always four levels deep: visual type, then style preset, then formatting card, then an array of property objects.
The visual type is the internal name, for example lineChart, clusteredColumnChart, tableEx (table), pivotTable (matrix), card, kpi, textSlicer or page. An asterisk targets every visual type.
The style preset is "*" for the default style, or a name in quotes to create a named preset that report authors can pick from the Style presets dropdown in the format pane.
The card is the formatting section, such as title, background, border, legend or categoryAxis. An asterisk targets properties in every card, which is how you set wordWrap or a font size everywhere.
The card name in JSON doesn't always match the label in the format pane. Two reliable ways to find the right name: autocomplete from the schema, or format a visual by hand, save the report as PBIP, and read that visual's objects node in its visual.json. Learn walks through the second method: enable "Copy object names when right clicking on report visuals" in Options, copy the visual's name, and search for it in the project folder.
Since the 2.139 schema, Power BI strictly enforces that every card under visualStyles > * > * is an array of objects whose properties are numbers, booleans, strings or structured values such as colour fills. A bare object instead of an array is the classic cause of a long, confusing validation error.
visualStyles excerpt
"visualStyles": {
"*": {
"*": {
"*": [{ "wordWrap": true }],
"background": [{ "show": false, "transparency": 100 }],
"border": [{ "show": false }],
"dropShadow": [{ "show": false }],
"title": [{ "fontSize": 12, "fontColor": { "solid": { "color": "foreground" } } }]
}
},
"columnChart": {
"*": { "stylePreset": [{ "name": "Clean" }] },
"Clean": {
"legend": [{ "position": "Top" }],
"valueAxis": [{ "gridlineStyle": "dotted" }]
}
}
}Embed a page background in the theme
The page visual type styles the canvas itself. Its background card takes a colour, a transparency and an image object with three fields: name (a label), url (a base64 data URI) and scaling. outspace styles the wallpaper outside the canvas.
Use "Fill" for scaling. The JSON scaling values don't match the format pane labels: the schema maps JSON "Normal" to the pane's Fit and JSON "Fit" to Stretch, while "Fill" is Fill in both. With an image exported at the canvas aspect ratio (1280 × 720 or 2560 × 1440 for the default page), Fill covers the canvas exactly.
Keep the image small. Base64 adds about a third to the file size, and the whole theme is stored in the report. Compress the PNG before encoding it, and prefer 1× for photographic backgrounds.
In the example the data URI is shortened; a real one is a long base64 string. The VizForge Design Studio and Theme Lab both export a complete file with the encoded image and transparent visual containers already set.
page background excerpt
"visualStyles": {
"page": {
"*": {
"background": [{
"color": { "solid": { "color": "#0B1220" } },
"transparency": 0,
"image": {
"name": "Brand background",
"url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
"scaling": "Fill"
}
}],
"outspace": [{ "color": { "solid": { "color": "#0B1220" } }, "transparency": 0 }]
}
}
}Import, test and fix a theme
In current Power BI Desktop, themes live on the Design ribbon: pick a built-in theme from the Themes gallery, or select Import theme and choose your JSON file. Customize theme opens the Theme pane, and Download theme exports the current theme. Older Desktop builds had the same commands under View > Themes, where importing was called Browse for themes. In the Power BI service, use the Theme pane in edit mode.
Power BI shows a success dialog, or an error naming the property it couldn't read. Fix the property and import again.
Two behaviours explain most "the theme didn't apply" reports. First, visuals formatted by hand keep their manual formatting; select the visual and use Reset to default in the format pane to hand it back to the theme. Be aware that Reset to default also clears button and image actions, conditional formatting rules and data-bound images on that visual. Second, importing a theme replaces the report's current custom theme entirely, including tweaks made in the Customize theme dialog.
Themes can't contain conditional formatting rules, because those depend on fields in a specific model. Apply them per visual after the theme.
Checklist before you share a theme
Validate against the current schema file and fix every warning.
Check contrast. Text classes and structural colours should reach 4.5:1 against the colours they sit on, which is the threshold in Microsoft's report accessibility checklist.
Test a dark theme on a table, a matrix, a slicer and a line chart with data labels on. Those four expose missing structural colours fastest.
Keep the series order deliberate: brand colour first, a clearly different second colour, and avoid red-green pairs that colour-blind viewers can't separate.
Version the file. Teams that save reports as PBIP keep the theme in the report's StaticResources/RegisteredResources folder, where it diffs like any other JSON in Git.
If you want a head start, the Theme Lab builds a schema-valid theme from a few brand colours and checks contrast as you go, and the theme gallery has ready-made themes you can download and import.
FAQ
What is the latest Power BI theme JSON schema?
reportThemeSchema-2.159.json, published for the October 2026 Power BI Desktop release (exploration version 5.78), in the microsoft/powerbi-desktop-samples repository on GitHub. Microsoft adds a new file each monthly release, mostly with additive changes.
Which properties are required in a Power BI theme?
Only name. Everything else, including dataColors, structural colours, textClasses and visualStyles, is optional and overrides Power BI's base theme only where you set it.
How do I import a theme in Power BI Desktop?
Design ribbon > Import theme, then choose the JSON file. You can also go through Customize theme > Theme settings > Import theme. Older builds used View > Themes > Browse for themes.
Why didn't my theme change some visuals?
Those visuals have manual formatting, which wins over the theme. Select the visual and choose Reset to default in the format pane. That also removes its conditional formatting and button or image actions, so reapply those afterwards.
Can a theme include a background image?
Yes. Under visualStyles > page > * > background, add an image object with a name, a base64 data URI as url, and scaling set to Fill.
Sources
- Microsoft Learn: Create custom report themes in Power BI Desktop
- Microsoft Learn: Use report themes in Power BI
- GitHub: Report Theme JSON Schema (microsoft/powerbi-desktop-samples)
- Microsoft Learn: Design Power BI reports for accessibility
Related reading
Build a schema-valid theme from brand colours with live contrast checks.
Ready-made, AA-contrast themes you can download and import.
Design the page, export a theme with the background embedded.
Step-by-step import, test and reset in Power BI Desktop.
Exact pixels for every page type before you embed an image.
Where the theme lives in a project, and how to edit it in Git.
Base theme precedence, 1920×1080 pages, Update theme banner, before/after JSON.
About the author
Nawaf Sharaf · Founder & Reliability Engineer
Nawaf is a reliability engineer and long-time Power BI practitioner, and the founder of VizForge. He builds the product solo — the AI generation pipeline, the visual code generator, and this site — from the perspective of someone who has spent years shipping Power BI reports in production.
Cite this article as:
VizForge. “Power BI Theme JSON: A Practical Guide to Schema 2.159 (2026).” November 4, 2026. https://vizforge.ai/blog/power-bi-theme-json-guide