PBIR Conditional Formatting Reference
Three approaches: measure-based (flexible), FillRule gradients (no DAX), and rule-based Conditional (UI-generated).
Approach Matrix
| Approach | Best For | Pros | Cons |
|---|---|---|---|
| Measure-based | Custom logic, theme colors | Full DAX, readable | Requires extension measure |
linearGradient2 / linearGradient3 |
Color scales | No DAX | Gradients only |
Conditional.Cases |
UI-portable rules | Power BI UI round-trips | Verbose |
Supported Properties
Not every property accepts measure expressions. These do:
fill, borderColor, defaultColor, fontColor, color, backgroundColor, lineColor, markerColor, strokeColor, text, titleText, fontSize, strokeWidth, weight, transparency, radius, url, good, bad, neutral, target, icon
Everything else is literal-only or ThemeDataColor.
dataViewWildcard Selector
The key to per-point formatting.
matchingOption |
Behavior |
|---|---|
0 |
Identities + totals (series-level) |
1 |
Per data point (most common for CF) |
2 |
Totals only |
"selector": {"data": [{"dataViewWildcard": {"matchingOption": 1}}]}
Wrong for per-point: "selector": {"metadata": "Sales.Revenue"} — evaluates once per series.
Two-Entry Array Pattern (Required)
dataPoint, lineStyles, error require a two-entry array: base entry + conditional entry.
"dataPoint": [
{"properties": {}},
{
"properties": {
"fill": {"solid": {"color": {"expr": {"Measure": {
"Expression": {"SourceRef": {"Schema": "extension", "Entity": "_Formatting"}},
"Property": "Bar Color"
}}}}}
},
"selector": {"data": [{"dataViewWildcard": {"matchingOption": 1}}]}
}
]
Extension Measure (for color CF)
Defined in Report.Report/definition/reportExtensions.json. dataType MUST be "Text" for color measures. Must attach to an EXISTING entity from the model.
{
"name": "extension",
"entities": [{
"name": "_Formatting",
"measures": [{
"name": "Bar Color",
"dataType": "Text",
"expression": "SWITCH(TRUE(), [Value]<10, \"bad\", [Value]<50, \"neutral\", \"good\")"
}]
}]
}
Theme color names returned by measures: "bad", "good", "neutral", "minColor", "midColor", "maxColor".
Measure Reference in CF Expressions
{"expr": {"Measure": {
"Expression": {"SourceRef": {"Schema": "extension", "Entity": "_Formatting"}},
"Property": "Bar Color"
}}}
"Schema": "extension" is required for report-level extension measures. Omit for model measures.
Pattern — Bar / Column Fill
"dataPoint": [
{"properties": {}},
{
"properties": {
"fill": {"solid": {"color": {"expr": {"Measure": {
"Expression": {"SourceRef": {"Schema": "extension", "Entity": "_Formatting"}},
"Property": "Bar Color"
}}}}}
},
"selector": {"data": [{"dataViewWildcard": {"matchingOption": 1}}]}
}
]
Pattern — linearGradient2 (Two-Color)
Data-driven (scale to observed range):
{"FillRule": {"linearGradient2": {
"min": {"color": {"Literal": {"Value": "'minColor'"}}},
"max": {"color": {"Literal": {"Value": "'maxColor'"}}},
"nullColoringStrategy": {"strategy": {"Literal": {"Value": "'asZero'"}}}
}}}
Explicit bounds (fixed thresholds):
{"FillRule": {"linearGradient2": {
"min": {"color": {"Literal": {"Value": "'minColor'"}}, "value": {"Literal": {"Value": "0D"}}},
"max": {"color": {"Literal": {"Value": "'maxColor'"}}, "value": {"Literal": {"Value": "1D"}}},
"nullColoringStrategy": {"strategy": {"Literal": {"Value": "'asZero'"}}, "color": {"Literal": {"Value": "'#FFFFFF'"}}}
}}}
Pattern — linearGradient3 (Diverging)
{"FillRule": {"linearGradient3": {
"min": {"color": {"Literal": {"Value": "'minColor'"}}, "value": {"Literal": {"Value": "-1D"}}},
"mid": {"color": {"Literal": {"Value": "'neutral'"}}, "value": {"Literal": {"Value": "0D"}}},
"max": {"color": {"Literal": {"Value": "'maxColor'"}}, "value": {"Literal": {"Value": "1D"}}},
"nullColoringStrategy": {"strategy": {"Literal": {"Value": "'asZero'"}}}
}}}
Pattern — Line Segment Colors (Single-Series Only)
Multi-series line charts cannot use segment coloring. Measure must return hex.
"lineStyles": [
{"properties": {"segmentGradient": {"expr": {"Literal": {"Value": "true"}}}}},
{
"properties": {
"strokeColor": {"solid": {"color": {"expr": {"Measure": {
"Expression": {"SourceRef": {"Schema": "extension", "Entity": "_Formatting"}},
"Property": "Line Color"
}}}}}
},
"selector": {"data": [{"dataViewWildcard": {"matchingOption": 1}}]}
}
]
segmentGradient only affects strokeColor. It does NOT work with lineStyle, strokeWidth, or markerFill.
Pattern — Axis Label Colors
No selector needed.
"categoryAxis": [{
"properties": {
"labelColor": {"solid": {"color": {"expr": {"Measure": {
"Expression": {"SourceRef": {"Schema": "extension", "Entity": "_Formatting"}},
"Property": "Axis Color"
}}}}}
}
}]
Pattern — Marker Transparency (0-100)
Marker color / shape / size do NOT support CF. Transparency does.
"markers": [
{"properties": {"borderShow": {"expr": {"Literal": {"Value": "false"}}}}},
{
"properties": {
"transparency": {"expr": {"Measure": {
"Expression": {"SourceRef": {"Schema": "extension", "Entity": "_Measures"}},
"Property": "Marker Opacity"
}}}
},
"selector": {"data": [{"dataViewWildcard": {"matchingOption": 1}}]}
}
]
Pattern — Rule-Based Conditional
{"expr": {"Conditional": {"Cases": [
{"Condition": {...}, "Value": {"Literal": {"Value": "'#FF0000'"}}},
{"Condition": {...}, "Value": {"Literal": {"Value": "'#00FF00'"}}}
]}}}
Cases evaluated in order; first match wins.
ComparisonKind Codes
| Value | Operator |
|---|---|
0 |
Equal |
1 |
Greater than |
2 |
Greater than or equal |
3 |
Less than or equal |
4 |
Less than |
Logical Wrappers
{"And": {"Left": {...}, "Right": {...}}}
{"Or": {"Left": {...}, "Right": {...}}}
{"Not": {"Expression": {...}}}
ScopedEval + AllRolesRef (Global Context)
Removes filter context for global min/max:
{"ScopedEval": {"Expression": {"Measure": {...}}, "Scope": [{"AllRolesRef": {}}]}}
Data Bars (table/matrix columns)
"dataBars": {
"positiveColor": {"solid": {"color": {"expr": {"Literal": {"Value": "'#E1EBF2'"}}}}},
"negativeColor": {"solid": {"color": {"expr": {"Literal": {"Value": "'#E5B97D'"}}}}},
"axisColor": {"solid": {"color": {"expr": {"Literal": {"Value": "'#FFFFFF'"}}}}},
"reverseDirection": {"expr": {"Literal": {"Value": "false"}}},
"hideText": {"expr": {"Literal": {"Value": "false"}}}
}
Conditional Icons
"icon": {
"kind": "Icon",
"layout": {"expr": {"Literal": {"Value": "'IconOnly'"}}},
"value": {"expr": {"Conditional": {"Cases": [
{"Condition": {"Comparison": {"ComparisonKind": 4, "Left": {"Measure": {...}}, "Right": {"Literal": {"Value": "0D"}}}},
"Value": {"Literal": {"Value": "'SymbolMedium'"}}}
]}}}
}
Custom icon from a URL
The block above is the Rules format style, driving a built-in icon set. The other style, Field value, points at a column of image URLs and renders those instead of a built-in icon — the way to get an arbitrary custom icon into a table or matrix cell.
- The URL may be an anonymously accessible web URL, or a OneLake file
URL:
https://onelake.dfs.fabric.microsoft.com/{workspace-id}/{item-id}/Files/{path-to-image} - Icons must be BMP, JPG, JPEG, GIF, PNG or SVG.
- Desktop path: field dropdown → Conditional formatting → Icons → Format style = Field value. Icon layout still controls left / right of the value or icon-only.
Two limits ride along when the URL is a OneLake one — Power BI loads it under each viewer's Entra identity, so:
- Viewers need Read on the lakehouse item and OneLake Read on the folder holding the image. Access to the report does not grant it.
- Publish to web and anonymous embed cannot use OneLake URLs at all — they
have no identity to authenticate with. Use an anonymously accessible web URL
for reports headed there. See
powerbi-report-authoring/references/image.mdfor the full OneLake image-source model.
The
visual.jsonencoding for the Field value icon source is deliberately not given here — it was not observed against a real PBIP export, and this skill's property paths are only worth having when they are verified. The block above is the Rules style and does not carry over unchanged.
Gotchas
| Issue | Cause | Fix |
|---|---|---|
| All points get same color | metadata selector used |
Switch to dataViewWildcard with matchingOption: 1 |
| CF works intermittently | Single-entry array with selector | Use two-entry array pattern |
| Measure rejected as color | dataType not "Text" in reportExtensions.json |
Set "dataType": "Text" |
| Extension measure not found | Created new entity in reportExtensions.json | Entities must already exist in the semantic model |
| Line segment colors don't work | Chart has multiple series in Y/Y2 | Segment coloring requires a single series |
| Marker color CF ignored | Marker fill/shape/size don't support CF | Use transparency instead |
segmentGradient + strokeWidth silently fails |
Only strokeColor is supported |
Don't combine |
reportExtensions.json deserialization fails |
Empty entities: [] |
Delete the file entirely when no extension measures exist |
title / legend selector ignored |
These objects don't accept selectors | Apply globally (no selector) |
| Gradient midpoint shifts unexpectedly | Data-driven bounds when fixed needed | Switch to explicit bounds form with value on min/mid/max |
AllRolesRef scope wrong place |
Nested incorrectly | ScopedEval.Scope: [{"AllRolesRef": {}}] at the outer wrapper |
| URL-sourced custom icons vanish in Publish to web | The column holds OneLake URLs, which cannot authenticate anonymously | Use anonymously accessible web URLs for any report published to web or anonymously embedded |
Reference
- Microsoft Learn: Apply conditional table formatting in Power BI
- Microsoft Learn: Format by field value (color expression measures)
- Microsoft Learn: Tips and tricks for color formatting
- Comprehensive MS Learn link bundle (CF user concept / measure pattern / gradient scales / theme tokens / PBIR file format): references/REFERENCE.md
See also
pbir-visual-json— selectors, expressions, literal suffixespbir-themes—ThemeDataColorand theme token resolution