PBIR visual.json Reference
Path: Report.Report/definition/pages/{PageName}/visuals/{VisualName}/visual.json
Top-Level Structure
| Property |
Type |
Required |
Notes |
$schema |
string |
yes |
.../visualContainer/2.7.0/schema.json |
name |
string |
yes |
Stable visual ID — referenced by bookmarks, interactions |
position |
object |
yes |
x, y, z, width, height, tabOrder |
visual |
object |
one of |
Regular visual — mutually exclusive with visualGroup |
visualGroup |
object |
one of |
Group container |
parentGroupName |
string |
no |
Set on children of a visualGroup |
filterConfig |
object |
no |
Visual-scoped filters — sibling of visual, NOT nested |
isHidden |
boolean |
no |
Root-level. Visual still processes data; common for bookmark toggles |
position
{"x": 100, "y": 50, "z": 1000, "width": 400, "height": 300, "tabOrder": 0}
z layer order: higher = front. Common values 0, 1000, 2000, 3000, 5000, 8000, 15000.
visual Object
| Property |
Notes |
visualType |
See visual type table below |
query.queryState |
Role → projections map |
query.sortDefinition |
sort[] + isDefaultSort |
objects |
Visual-specific formatting (axes, legend, dataPoint, labels, lineStyles) |
visualContainerObjects |
Container formatting (title, subTitle, background, border, dropShadow, padding, divider, visualHeader, visualTooltip) |
drillFilterOtherVisuals |
boolean |
syncGroup |
Slicer cross-page sync: groupName, fieldChanges, filterChanges |
expansionStates |
pivotTable row/column expansion |
Critical: objects vs visualContainerObjects are distinct in schema 2.4.0+. Container properties in objects fail silently. visualContainerObjects at root errors.
Expression Literal Suffixes
All formatting values inside visual.json use {"expr": {"Literal": {"Value": "..."}}} wrappers. Theme JSON uses bare values.
| Type |
Example |
Notes |
| String |
"'smooth'" |
Inner single quotes required |
| Double |
"14D" |
Font sizes, percentages, most numerics |
| Integer |
"14L" |
Pixel counts, enum values, labelPrecision |
| Decimal |
"2.4M" |
Money/decimal precision |
| Boolean |
"true" |
Lowercase, no quotes, no suffix |
| DateTime |
"datetime'2024-01-15T00:00:00.0000000'" |
Closing ' required |
| Hex color |
"'#FF0000'" |
Inner single quotes; 6-digit RGB or 8-digit ARGB |
| Null |
"null" |
Lowercase, no quotes |
Non-literal expressions:
| Type |
Shape |
| Theme color |
{"expr": {"ThemeDataColor": {"ColorId": 0, "Percent": 0}}} |
| Extension measure |
{"expr": {"Measure": {"Expression": {"SourceRef": {"Schema": "extension", "Entity": "_Formatting"}}, "Property": "Color"}}} |
Gotchas: transparency uses D normally but L inside dropShadow. labelPrecision always L, labelDisplayUnits always D. String escaping: single quotes doubled ("'O''Brien'"). Font fallback chains: "'''Segoe UI Semibold'', helvetica, sans-serif'".
(Yes — three single quotes. The outer pair wraps the SQExpr string literal; the inner pair escapes the space-containing font name. Not a typo.)
Field Reference Patterns
| Pattern |
Shape |
| Column |
{"Column": {"Expression": {"SourceRef": {"Entity": "Table"}}, "Property": "Col"}} |
| Measure (model) |
{"Measure": {"Expression": {"SourceRef": {"Entity": "Table"}}, "Property": "M"}} |
| Measure (extension) |
{"Measure": {"Expression": {"SourceRef": {"Schema": "extension", "Entity": "_Fmt"}}, "Property": "M"}} |
| Aggregation |
{"Aggregation": {"Expression": {"Column": {...}}, "Function": 0}} |
| Hierarchy level |
{"HierarchyLevel": {"Expression": {"Hierarchy": {...}}, "Level": "Level"}} |
| SparklineData |
{"SparklineData": {"Measure": {...}, "Groupings": [{"Column": {...}}]}} |
QueryAggregateFunction: 0=Sum, 1=Avg, 2=DistinctCount, 3=Min, 4=Max, 5=Count, 6=Median, 7=StdDev, 8=Var
Filter SourceRef gotcha: inside filter Where conditions, SourceRef uses "Source": "alias" (from From), NOT "Entity". Query projections use "Entity".
Visual Types and Query Roles
| visualType |
Roles |
card |
Values |
cardVisual (new card) |
Data |
tableEx |
Values |
pivotTable |
Rows, Columns, Values |
slicer / advancedSlicerVisual |
Values |
pieChart / donutChart |
Category, Y |
lineChart |
Category, Y, Y2 (combo) |
areaChart / stackedAreaChart |
Category, Y, Series |
barChart / clusteredBarChart / hundredPercentStackedBarChart |
Category, Y |
columnChart / clusteredColumnChart / hundredPercentStackedColumnChart |
Category, Y |
lineClusteredColumnComboChart / lineStackedColumnComboChart |
Category, Y, Y2 |
ribbonChart / waterfallChart |
Category, Y |
scatterChart |
Category, X, Y, Size, Tooltips |
gauge |
Y, TargetValue |
kpi |
Indicator, Goal, TrendLine |
textbox |
none (uses objects.general.paragraphs) |
shape / actionButton / image |
none |
scriptVisual / pythonVisual |
Values |
PBI_CV_<GUID> |
varies (custom visuals) |
deneb<GUID> |
dataset |
Projection Properties
| Property |
Notes |
queryRef |
Table.Field — internal reference |
nativeQueryRef |
Display label |
displayName |
Optional override |
active |
Boolean — hierarchy level expanded |
Visual calculations (NativeVisualCalculation) always have queryRef: "select".
sortDefinition
"sortDefinition": {
"sort": [{
"field": {"Measure": {"Expression": {"SourceRef": {"Entity": "Sales"}}, "Property": "Revenue"}},
"direction": "Descending"
}],
"isDefaultSort": true
}
Slicer Default Selected Values
Store in objects.general.properties.filter — NOT filterConfig. filterConfig filters data going into the slicer; objects.general.properties.filter pre-selects values.
Hiding Visuals and Fields
- Hide whole visual:
"isHidden": true at root (outside visual).
- Hide fields from display: omit from
queryState — still referenceable by extension measures / filters.
Visual Groups
{
"name": "kpi_group",
"position": {"x": 0, "y": 0, "z": 0, "width": 800, "height": 400},
"visualGroup": {
"displayName": "KPI Section",
"groupMode": "ScaleMode",
"objects": {"background": [...], "general": [...], "lockAspect": [...]}
}
}
groupMode: ScaleMode (scale contents) or ScrollMode. Children set parentGroupName. Group objects limited to background, general, lockAspect.
Table / Matrix Column Widths
"columnWidth": [{
"properties": {"value": {"expr": {"Literal": {"Value": "215D"}}}},
"selector": {"metadata": "Orders.Order Lines"}
}]
mobile.json
Optional sibling file at visuals/{VisualName}/mobile.json. Mirrors visual.json position fields with mobile coordinates. Typically authored via Desktop.
Gotchas
| Issue |
Cause |
Fix |
| Container props silently ignored |
Placed in objects instead of visualContainerObjects |
Move title/border/background/dropShadow/padding to visualContainerObjects |
Root-level error on visualContainerObjects |
Placed at visual.json root instead of inside visual |
Nest under visual (container objects still live inside visual) |
filterConfig ignored |
Nested inside visual |
Must be sibling of visual at root of visual.json |
| Slicer default values don't stick |
Stored in filterConfig |
Use objects.general.properties.filter |
transparency parse error in dropShadow |
Used D suffix |
Use L inside dropShadow |
| String literal unterminated |
Missing closing single quote on datetime'...' |
Always close datetime literals with ' |
| Filter Where condition broken |
Used SourceRef.Entity instead of SourceRef.Source |
Reference the alias from From[] |
| Font fallback chain broken |
Single-level quotes |
Triple-quote primary font: "'''Segoe UI Semibold'', sans-serif'" |
labelPrecision rejected |
Used D suffix |
Always L |
labelDisplayUnits rejected |
Used L suffix |
Always D |
| Sparkline formatting ignored |
selector.metadata doesn't match projection queryRef |
Copy exact SparklineData(...) queryRef into selector |
visual and visualGroup both present |
Mutually exclusive |
Pick one per visual.json |
April 2026 visual changes
| Visual |
Change |
Authoring impact |
cardVisual / slicer (button-slicer / list-slicer modes) |
Multicard layout exposes a Fixed size toggle (exact pixel dimensions). Mutually exclusive with Fit to space (renamed from Autogrid). |
Property names not yet documented as a JSON-schema keys — verify in a saved visual.json before authoring. Existing reports with Autogrid formatting will surface under Fit to space in the Format pane. |
cardVisual |
Theme JSON keys paddingUniform (default 12) and backgroundTransparency documented under cardVisual style preset. Category headers participate in Edit interactions; Multi-category layout Autogrid capped at 4 rows (toggle off for more). |
When clearing legacy padding, write "paddingUniform": 0. Theme schema URL is reportThemeSchema-2.149.json. |
narrativeVisual (smart narrative) |
Defaults to Copilot mode for users with a Copilot license. Character limit raised to 10,000. |
Narrative visual.json content beyond 10,000 chars should now load; treat default-mode probes carefully — un-licensed users still land in classic mode. |
Reference
See also
pbir-themes — theme value conventions (bare vs wrapped literals)
pbir-conditional-formatting — CF patterns inside visual.json objects
pbir-filters — filter body shape and SourceRef.Source rule
pbir-bookmarks — bookmarks reference the visual's root-level name
1---2name: pbir-visual-json3description: Use when editing visual.json inside a Power BI PBIR report's visuals/ folder. Covers top-level structure (name, position, visual vs visualGroup mutually exclusive, filterConfig sibling NOT child of visual, root-level isHidden for bookmark toggles), expression literal suffixes — string 'text', double 14D, integer 14L, decimal 2.4M, hex '#FF0000', datetime literal, null — with exceptions (transparency uses L inside dropShadow, labelPrecision L, labelDisplayUnits D, triple-quoted font fallback chains), field reference patterns (Column, Measure, Aggregation, HierarchyLevel, SparklineData), visual-type to query-role map (card, tableEx, pivotTable, slicer, lineChart, barChart, kpi, scatterChart), objects vs visualContainerObjects split, sortDefinition, slicer default values via objects.general.properties.filter, visual groups, table column widths.4---56## PBIR visual.json Reference78Path: `Report.Report/definition/pages/{PageName}/visuals/{VisualName}/visual.json`910### Top-Level Structure1112| Property | Type | Required | Notes |13|---|---|---|---|14| `$schema` | string | yes | `.../visualContainer/2.7.0/schema.json` |15| `name` | string | yes | Stable visual ID — referenced by bookmarks, interactions |16| `position` | object | yes | `x`, `y`, `z`, `width`, `height`, `tabOrder` |17| `visual` | object | one of | Regular visual — mutually exclusive with `visualGroup` |18| `visualGroup` | object | one of | Group container |19| `parentGroupName` | string | no | Set on children of a `visualGroup` |20| `filterConfig` | object | no | Visual-scoped filters — sibling of `visual`, NOT nested |21| `isHidden` | boolean | no | Root-level. Visual still processes data; common for bookmark toggles |2223### position2425```json26{"x": 100, "y": 50, "z": 1000, "width": 400, "height": 300, "tabOrder": 0}27```2829`z` layer order: higher = front. Common values `0, 1000, 2000, 3000, 5000, 8000, 15000`.3031### visual Object3233| Property | Notes |34|---|---|35| `visualType` | See visual type table below |36| `query.queryState` | Role → projections map |37| `query.sortDefinition` | `sort[]` + `isDefaultSort` |38| `objects` | Visual-specific formatting (axes, legend, dataPoint, labels, lineStyles) |39| `visualContainerObjects` | Container formatting (title, subTitle, background, border, dropShadow, padding, divider, visualHeader, visualTooltip) |40| `drillFilterOtherVisuals` | boolean |41| `syncGroup` | Slicer cross-page sync: `groupName`, `fieldChanges`, `filterChanges` |42| `expansionStates` | pivotTable row/column expansion |4344**Critical**: `objects` vs `visualContainerObjects` are distinct in schema 2.4.0+. Container properties in `objects` fail silently. `visualContainerObjects` at root errors.4546### Expression Literal Suffixes4748All formatting values inside `visual.json` use `{"expr": {"Literal": {"Value": "..."}}}` wrappers. Theme JSON uses bare values.4950| Type | Example | Notes |51|---|---|---|52| String | `"'smooth'"` | Inner single quotes required |53| Double | `"14D"` | Font sizes, percentages, most numerics |54| Integer | `"14L"` | Pixel counts, enum values, `labelPrecision` |55| Decimal | `"2.4M"` | Money/decimal precision |56| Boolean | `"true"` | Lowercase, no quotes, no suffix |57| DateTime | `"datetime'2024-01-15T00:00:00.0000000'"` | Closing `'` required |58| Hex color | `"'#FF0000'"` | Inner single quotes; 6-digit RGB or 8-digit ARGB |59| Null | `"null"` | Lowercase, no quotes |6061Non-literal expressions:6263| Type | Shape |64|---|---|65| Theme color | `{"expr": {"ThemeDataColor": {"ColorId": 0, "Percent": 0}}}` |66| Extension measure | `{"expr": {"Measure": {"Expression": {"SourceRef": {"Schema": "extension", "Entity": "_Formatting"}}, "Property": "Color"}}}` |6768**Gotchas**: `transparency` uses `D` normally but `L` inside `dropShadow`. `labelPrecision` always `L`, `labelDisplayUnits` always `D`. String escaping: single quotes doubled (`"'O''Brien'"`). Font fallback chains: `"'''Segoe UI Semibold'', helvetica, sans-serif'"`.69(Yes — three single quotes. The outer pair wraps the SQExpr string literal; the inner pair escapes the space-containing font name. Not a typo.)7071### Field Reference Patterns7273| Pattern | Shape |74|---|---|75| Column | `{"Column": {"Expression": {"SourceRef": {"Entity": "Table"}}, "Property": "Col"}}` |76| Measure (model) | `{"Measure": {"Expression": {"SourceRef": {"Entity": "Table"}}, "Property": "M"}}` |77| Measure (extension) | `{"Measure": {"Expression": {"SourceRef": {"Schema": "extension", "Entity": "_Fmt"}}, "Property": "M"}}` |78| Aggregation | `{"Aggregation": {"Expression": {"Column": {...}}, "Function": 0}}` |79| Hierarchy level | `{"HierarchyLevel": {"Expression": {"Hierarchy": {...}}, "Level": "Level"}}` |80| SparklineData | `{"SparklineData": {"Measure": {...}, "Groupings": [{"Column": {...}}]}}` |8182`QueryAggregateFunction`: `0`=Sum, `1`=Avg, `2`=DistinctCount, `3`=Min, `4`=Max, `5`=Count, `6`=Median, `7`=StdDev, `8`=Var8384**Filter SourceRef gotcha**: inside filter `Where` conditions, SourceRef uses `"Source": "alias"` (from `From`), NOT `"Entity"`. Query projections use `"Entity"`.8586### Visual Types and Query Roles8788| visualType | Roles |89|---|---|90| `card` | Values |91| `cardVisual` (new card) | Data |92| `tableEx` | Values |93| `pivotTable` | Rows, Columns, Values |94| `slicer` / `advancedSlicerVisual` | Values |95| `pieChart` / `donutChart` | Category, Y |96| `lineChart` | Category, Y, Y2 (combo) |97| `areaChart` / `stackedAreaChart` | Category, Y, Series |98| `barChart` / `clusteredBarChart` / `hundredPercentStackedBarChart` | Category, Y |99| `columnChart` / `clusteredColumnChart` / `hundredPercentStackedColumnChart` | Category, Y |100| `lineClusteredColumnComboChart` / `lineStackedColumnComboChart` | Category, Y, Y2 |101| `ribbonChart` / `waterfallChart` | Category, Y |102| `scatterChart` | Category, X, Y, Size, Tooltips |103| `gauge` | Y, TargetValue |104| `kpi` | Indicator, Goal, TrendLine |105| `textbox` | none (uses `objects.general.paragraphs`) |106| `shape` / `actionButton` / `image` | none |107| `scriptVisual` / `pythonVisual` | Values |108| `PBI_CV_<GUID>` | varies (custom visuals) |109| `deneb<GUID>` | dataset |110111### Projection Properties112113| Property | Notes |114|---|---|115| `queryRef` | `Table.Field` — internal reference |116| `nativeQueryRef` | Display label |117| `displayName` | Optional override |118| `active` | Boolean — hierarchy level expanded |119120Visual calculations (`NativeVisualCalculation`) always have `queryRef: "select"`.121122### sortDefinition123124```json125"sortDefinition": {126 "sort": [{127 "field": {"Measure": {"Expression": {"SourceRef": {"Entity": "Sales"}}, "Property": "Revenue"}},128 "direction": "Descending"129 }],130 "isDefaultSort": true131}132```133134### Slicer Default Selected Values135136Store in `objects.general.properties.filter` — NOT `filterConfig`. `filterConfig` filters data going *into* the slicer; `objects.general.properties.filter` pre-selects values.137138### Hiding Visuals and Fields139140- Hide whole visual: `"isHidden": true` at root (outside `visual`).141- Hide fields from display: omit from `queryState` — still referenceable by extension measures / filters.142143### Visual Groups144145```json146{147 "name": "kpi_group",148 "position": {"x": 0, "y": 0, "z": 0, "width": 800, "height": 400},149 "visualGroup": {150 "displayName": "KPI Section",151 "groupMode": "ScaleMode",152 "objects": {"background": [...], "general": [...], "lockAspect": [...]}153 }154}155```156157`groupMode`: `ScaleMode` (scale contents) or `ScrollMode`. Children set `parentGroupName`. Group objects limited to `background`, `general`, `lockAspect`.158159### Table / Matrix Column Widths160161```json162"columnWidth": [{163 "properties": {"value": {"expr": {"Literal": {"Value": "215D"}}}},164 "selector": {"metadata": "Orders.Order Lines"}165}]166```167168### mobile.json169170Optional sibling file at `visuals/{VisualName}/mobile.json`. Mirrors `visual.json` position fields with mobile coordinates. Typically authored via Desktop.171172### Gotchas173174| Issue | Cause | Fix |175|---|---|---|176| Container props silently ignored | Placed in `objects` instead of `visualContainerObjects` | Move title/border/background/dropShadow/padding to `visualContainerObjects` |177| Root-level error on `visualContainerObjects` | Placed at `visual.json` root instead of inside `visual` | Nest under `visual` (container objects still live inside `visual`) |178| `filterConfig` ignored | Nested inside `visual` | Must be sibling of `visual` at root of visual.json |179| Slicer default values don't stick | Stored in `filterConfig` | Use `objects.general.properties.filter` |180| `transparency` parse error in dropShadow | Used `D` suffix | Use `L` inside `dropShadow` |181| String literal unterminated | Missing closing single quote on `datetime'...'` | Always close datetime literals with `'` |182| Filter Where condition broken | Used `SourceRef.Entity` instead of `SourceRef.Source` | Reference the alias from `From[]` |183| Font fallback chain broken | Single-level quotes | Triple-quote primary font: `"'''Segoe UI Semibold'', sans-serif'"` |184| `labelPrecision` rejected | Used `D` suffix | Always `L` |185| `labelDisplayUnits` rejected | Used `L` suffix | Always `D` |186| Sparkline formatting ignored | `selector.metadata` doesn't match projection `queryRef` | Copy exact `SparklineData(...)` queryRef into selector |187| `visual` and `visualGroup` both present | Mutually exclusive | Pick one per visual.json |188189### April 2026 visual changes190191| Visual | Change | Authoring impact |192|---|---|---|193| `cardVisual` / `slicer` (button-slicer / list-slicer modes) | Multicard layout exposes a **Fixed size** toggle (exact pixel dimensions). Mutually exclusive with **Fit to space** (renamed from `Autogrid`). | Property names not yet documented as a JSON-schema keys — verify in a saved visual.json before authoring. Existing reports with `Autogrid` formatting will surface under `Fit to space` in the Format pane. |194| `cardVisual` | Theme JSON keys `paddingUniform` (default 12) and `backgroundTransparency` documented under `cardVisual` style preset. Category headers participate in Edit interactions; Multi-category layout `Autogrid` capped at 4 rows (toggle off for more). | When clearing legacy padding, write `"paddingUniform": 0`. Theme schema URL is `reportThemeSchema-2.149.json`. |195| `narrativeVisual` (smart narrative) | Defaults to **Copilot mode** for users with a Copilot license. Character limit raised to **10,000**. | Narrative visual.json content beyond 10,000 chars should now load; treat default-mode probes carefully — un-licensed users still land in classic mode. |196197### Reference198199- Microsoft Learn: [Visualizations overview in Power BI](https://learn.microsoft.com/power-bi/visuals/power-bi-visualizations-overview)200- Microsoft Learn: [Visualization types in Power BI](https://learn.microsoft.com/power-bi/visuals/power-bi-visualization-types-for-reports-and-q-and-a)201- Microsoft Learn: [Power BI Desktop project — report folder](https://learn.microsoft.com/power-bi/developer/projects/projects-report)202- Microsoft Learn: [Card visual — Fixed size, Fit to space, theme keys](https://learn.microsoft.com/power-bi/visuals/power-bi-visualization-card)203- Microsoft Learn: [Smart narrative visual](https://learn.microsoft.com/power-bi/visuals/power-bi-visualization-smart-narrative)204- Comprehensive MS Learn link bundle (visual catalog → visualType / per-visual articles / visualGroup / custom visuals / PBIR file format): [references/REFERENCE.md](references/REFERENCE.md)205206### See also207208- `pbir-themes` — theme value conventions (bare vs wrapped literals)209- `pbir-conditional-formatting` — CF patterns inside visual.json `objects`210- `pbir-filters` — filter body shape and `SourceRef.Source` rule211- `pbir-bookmarks` — bookmarks reference the visual's root-level `name`