Power BI Custom Visuals Development
Custom Power BI visuals are web components — written in TypeScript, rendered with D3/SVG/Canvas/HTML, and packaged as a single .pbiviz file — that run sandboxed inside an iframe in Power BI Desktop and the Power BI service. You build them with the pbiviz command-line tool (the powerbi-visuals-tools npm package) against the typed powerbi-visuals-api. This skill covers the full lifecycle: scaffold → develop → debug → package → certify.
This is a knowledge plugin. It generates and reviews source files (visual.ts, capabilities.json, settings.ts, pbiviz.json) and drives the local pbiviz CLI — it does not require any MCP server or cloud credentials.
Prerequisites
- Node.js (current LTS) and npm. Install the toolchain globally:
npm i -g powerbi-visuals-tools@latest (provides the pbiviz command).
- A Power BI Pro or Premium Per User (PPU) account to test in the service, plus an IDE (VS Code recommended).
- Developer mode enabled — in Power BI Desktop (File ▸ Options ▸ Report settings ▸ Develop a visual, per session) or in the service (Developer settings ▸ Power BI Developer mode). See
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/environment-setup.md.
- For certification: a Partner Center account and a public/reviewable GitHub repository.
Choosing how to build
The pbiviz SDK is the most powerful path, but not always the right one. Pick the lightest approach that meets the need: SVG rendered from a DAX measure (inline sparklines/KPIs in tables, no visual to build), Deneb (declarative Vega/Vega-Lite, certified), the HTML Content visual, Charticulator (no-code), or the full pbiviz SDK (TypeScript + D3/React) when you need lifecycle control, a custom format pane, advanced interactivity, or AppSource distribution. The full decision guide and low-code patterns are in ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/building-approaches.md. The rest of this skill covers the SDK path in depth.
Deneb — declarative Vega / Vega-Lite (the no-build path)
Deneb is a certified custom visual that runs Vega and Vega-Lite JSON specs inside Power BI — no pbiviz toolchain, no build, yet with native cross-filtering, tooltips, context menus, and report-theme colors. Reach for it when the chart exists in the Vega ecosystem but not the Power BI core set and the user wants a certified result fast. Key facts:
- Bind data via the named dataset
dataset — { "data": { "name": "dataset" } } (Vega-Lite) or a dataset data source (Vega). Field names are the column display names from Deneb's Values well.
- Provider: Vega-Lite (concise
mark+encoding, parameters) for standard charts; Vega (explicit scales/signals/marks) for bespoke layouts and manual interactivity.
- Cross-filtering: enable it in Settings, then style on the injected
__selected__ field ('on'/'off'/'neutral'). Advanced (Vega-only) mode uses the pbiCrossFilterSelection signal with pbiCrossFilterApply(event, filter?, options?) / pbiCrossFilterClear() for brush/aggregate selection.
- Deneb expression functions:
pbiColor(index, shade?) (theme colors), pbiFormat(value, fmt, opts?) (Power BI format strings + locale), pbiPatternSVG(pattern, fg, bg) (texture fills, SVG mode).
- Responsive:
"width": "container", "height": "container", "autosize": { "type": "fit", "contains": "padding" }. Keep shared styling in the Config object; reuse charts via the template (usermeta) system.
- Certified-build limits: no external
data.url, remote images, or external fonts — all data flows through dataset.
Run /pbiviz-deneb to author or iterate a spec. Full reference: ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/deneb-vega.md; copy-paste specs: ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/deneb-specs.md.
The visual lifecycle at a glance
| Stage |
Command / artifact |
Reference |
| Set up environment |
npm i -g powerbi-visuals-tools@latest, enable dev mode |
references/environment-setup.md |
| Scaffold a project |
pbiviz new <name> |
references/project-structure.md |
| Declare data + format contract |
capabilities.json |
references/capabilities.md |
| Shape the incoming data |
dataViewMappings + parse options.dataViews[0] |
references/dataview-mapping.md |
| Render & handle lifecycle |
IVisual class in src/visual.ts |
references/visual-api.md |
| Build the Format pane |
getFormattingModel + formatting model utils |
references/formatting-model.md |
| Add interactivity |
selection, tooltips, context menu, drill, bookmarks |
references/interactivity.md |
| Live debug |
pbiviz start + Developer Visual |
command /pbiviz-debug |
| Test & lint |
ESLint + jasmine/karma unit tests |
references/testing.md |
| Package |
pbiviz package → dist/<name>.pbiviz |
references/packaging-certification.md |
| Certify & publish |
Partner Center + AppSource |
references/packaging-certification.md |
Project structure
pbiviz new <name> scaffolds a complete project. The files that matter most:
pbiviz.json — visual metadata: internal name, displayName, unique guid, visualClassName (must match your IVisual class name), version (four-part x.x.x.x), apiVersion, author, assets.icon, and the paths to capabilities.json and style/visual.less.
capabilities.json — the contract with the host: what data the visual accepts and what appears in the Format pane.
src/visual.ts — the IVisual implementation (your render code).
src/settings.ts — the formatting settings model (Format pane cards/slices).
style/visual.less — styles.
assets/icon.png — the Visualizations-pane icon, a 20×20 PNG.
tsconfig.json, package.json, package-lock.json, .eslintrc.
Full annotated layout and pbiviz.json field reference: ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/project-structure.md.
capabilities.json — the data and format contract
capabilities.json tells the host what kind of data the visual accepts and what customizable properties appear in the Format pane. From API v4.6.0 all root properties are optional except privileges, which is required (use "privileges": [] when the visual needs no special access).
Root objects:
privileges — special access the visual needs: WebAccess (external URLs — must be empty for certification), ExportContent (download to file), LocalStorage.
dataRoles — the field wells users drag data into. Each has a name, displayName, and kind: Grouping (discrete buckets), Measure (numeric), or GroupingOrMeasure.
dataViewMappings — how roles map into a DataView (categorical, table, matrix, or single), with conditions bounding how many fields each role accepts and a dataReductionAlgorithm (top/bottom/sample/window, default top at 1000, max 30000).
objects — Format pane properties. Each object/property name must exactly match a card/slice in your formatting model.
- Feature flags —
supportsHighlight, sorting, drilldown, expandCollapse, supportsLandingPage, supportsEmptyDataView, supportsKeyboardFocus, tooltips, advancedEditModeSupport, supportsMultiVisualSelection, subtotals, keepAllMetadataColumns.
Details and copy-paste blocks: ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/capabilities.md. Complete files: ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/capabilities-json.md.
DataView — reading the data
Each valid dataViewMappings entry produces a DataView delivered in update(options) as options.dataViews[0]. Power BI only populates the mapping types you declared.
single — one aggregated value (dataView.single.value). For KPI cards.
categorical — independent groupings + measures (dataView.categorical.categories[] and .values[]). The most common mapping for charts. Group values by a series role for hierarchical/series data; read groups with categorical.values.grouped().
table — a flat list of rows (dataView.table.columns[], dataView.table.rows[]). Do not assume row order.
matrix — hierarchical rows/columns as a tree of DataViewMatrixNode (dataView.matrix.rows.root, .columns.root, .valueSources). Supports expand/collapse of row headers (API 4.1+).
Always null-check the mapping (if (!dataView?.categorical?.values) return;) before reading — a user may not have populated every field well. Parsing patterns for every mapping type: ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/dataview-mapping.md.
The IVisual API
Every visual is a class implementing IVisual (named exactly as visualClassName in pbiviz.json):
export class Visual implements IVisual {
constructor(options: VisualConstructorOptions) { /* one-time setup */ }
public update(options: VisualUpdateOptions): void { /* render on every data/size/view change */ }
public getFormattingModel(): powerbi.visuals.FormattingModel { /* build the Format pane */ }
public destroy(): void { /* optional cleanup */ }
}
constructor(options) — runs once. Capture options.element (your DOM root) and options.host (the IVisualHost), and create long-lived services (createSelectionManager, createLocalizationManager, colorPalette, tooltipService, eventService).
update(options) — runs on every change. options.viewport is the size, options.dataViews the data, options.type flags the cause (Data | Resize | ViewMode | Style | ResizeEnd). Re-render here.
getFormattingModel() — returns the Format pane model (replaces the deprecated enumerateObjectInstances).
Host services (selection, tooltips, color palette, launchUrl, persistProperties, fetchMoreData, storageService, eventService, displayWarningIcon, acquireAADTokenService) are detailed in ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/visual-api.md.
Rendering Events API (required for certification): call host.eventService.renderingStarted(options) at the start of update, renderingFinished(options) when the DOM is fully drawn, and renderingFailed(options, reason) on error. This signals "export to PDF/PowerPoint" and automated tests that rendering is complete.
The modern Format pane (API 5.1+)
Use API version 5.1 or later and implement getFormattingModel. The recommended approach is the formatting model utils (powerbi-visuals-utils-formattingmodel):
- Declare a settings model in
src/settings.ts extending formattingSettings.Model, composed of cards (formattingSettings.SimpleCard / CompositeCard) → optional groups → slices (ToggleSwitch, NumUpDown, Slider, ColorPicker, ItemDropdown, AutoDropdown, FontControl, TextInput, AlignmentGroup, …). Card name must equal the object name and slice name must equal the property name in capabilities.json.
- In the constructor:
this.formattingSettingsService = new FormattingSettingsService(localizationManager?).
- In
update: this.settings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
- Implement
getFormattingModel() → return this.formattingSettingsService.buildFormattingModel(this.settings);
Property type ↔ capabilities value-type mapping, composite slices, conditional formatting (per-data-point colors via dataViewWildcard selectors + instanceKind), and reset-to-default: ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/formatting-model.md. Full settings.ts: ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/formatting-settings.md.
Interactivity
- Selection & cross-filtering — create an
ISelectionManager in the constructor and an ISelectionId per data point with host.createSelectionIdBuilder().withCategory(...) / .withSeries(...) / .withTable(...) / .withMatrixNode(...). Call selectionManager.select(id, multiSelect) on click; reflect selectionManager.getSelectionIds() visually. Support Ctrl-click for multi-select.
- Highlighting — set
"supportsHighlight": true and render the values[i].highlights array (non-highlighted portions dimmed) when other visuals cross-filter yours.
- Tooltips — declare
"tooltips" in capabilities and use host.tooltipService (or powerbi-visuals-utils-tooltiputils) to show/move/hide tooltips on pointer events.
- Context menu —
selectionManager.showContextMenu(selectionId, {x, y}, dataRole?) on contextmenu. The dataRole argument is required when the visual supports drilldown or expandCollapse.
- Drill-down / expand-collapse, bookmarks (register a selection callback, restore on
update), landing page (supportsLandingPage + supportsEmptyDataView), launchUrl, local storage, and the color palette are all covered in ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/interactivity.md.
Testing, linting, and security
Certification requires eslint, eslint-plugin-powerbi-visuals, and typescript in package.json, a clean npm audit (no high/moderate), and no JS console errors. Unit tests use jasmine + karma with powerbi-visuals-utils-testutils. Manipulate the DOM safely — never use innerHTML/D3.html() with user data, and avoid eval/Function/dynamic setTimeout. See ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/testing.md.
Packaging & certification
- Package:
pbiviz package writes dist/<name>.pbiviz. The description field in pbiviz.json must be filled in or the command fails. Bump the four-part version before each package.
- Certify: publish to AppSource via Partner Center, then optionally request certification. Requirements: latest API, a lowercase
certification Git branch matching the submitted package, OSS-only libraries, Rendering Events API support, no external network access (WebAccess empty/omitted), no minified code, and a clean pbiviz package --certification-audit. Full checklist: ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/packaging-certification.md.
Utility packages
Microsoft ships helper packages so you don't reinvent common chart plumbing: powerbi-visuals-utils-formattingmodel (Format pane), -dataviewutils, -formattingutils (number/date formatting + text measurement), -svgutils, -chartutils (axes/legend), -colorutils, -interactivityutils, -tooltiputils, -typeutils, and -testutils. Reference + common errors: ${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/utils-and-troubleshooting.md.
Reference files
| File |
Path |
Content |
| Building approaches |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/building-approaches.md |
Choosing SDK vs Deneb vs SVG-via-DAX vs HTML Content vs Charticulator; React + pbiviz MCP |
| Deneb (Vega/Vega-Lite) |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/deneb-vega.md |
Deneb editor, dataset binding, cross-filter (__selected__, pbiCrossFilterApply), pbiColor/pbiFormat/pbiPatternSVG, themes, templates, certified limits |
| Environment setup |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/environment-setup.md |
Node, pbiviz install, dev mode, account/SSL setup |
| Project structure |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/project-structure.md |
Folder layout, pbiviz.json, tsconfig, package.json |
| Capabilities |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/capabilities.md |
privileges, dataRoles, mappings, objects, feature flags |
| DataView mapping |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/dataview-mapping.md |
single/categorical/table/matrix parsing, reduction, conditions |
| Visual API |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/visual-api.md |
IVisual lifecycle, host services, rendering events |
| Formatting model |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/formatting-model.md |
Format pane, utils, slice types, conditional formatting |
| Interactivity |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/interactivity.md |
selection, tooltips, context menu, drill, bookmarks, landing page |
| Testing |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/testing.md |
ESLint, unit tests, debugging, security rules |
| Packaging & certification |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/packaging-certification.md |
pbiviz package, AppSource, certification checklist |
| Utils & troubleshooting |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/utils-and-troubleshooting.md |
utility packages, common errors and fixes |
Example files
| File |
Path |
Content |
| Visual (bar chart) |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/visual-ts-barchart.md |
Complete visual.ts: IVisual, D3, selection, tooltips, rendering events |
| capabilities.json |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/capabilities-json.md |
Complete capabilities for categorical, table, and matrix visuals |
| Formatting settings |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/formatting-settings.md |
settings.ts cards/groups/slices + conditional formatting |
| Config files |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/pbiviz-and-config.md |
pbiviz.json, tsconfig.json, package.json, .eslintrc |
| Scaffold walkthrough |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/scaffold-walkthrough.md |
End-to-end: new → develop → start → package → certify |
| Deneb specs |
${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/deneb-specs.md |
Copy-paste Vega/Vega-Lite specs: cross-filter bar, rolling-mean line, bullet, pattern fills, advanced-mode Vega, theme config, template usermeta |
1---2name: power-bi-custom-visuals-development3description: This skill should be used when the user asks about developing, building, debugging, packaging, or certifying a custom Power BI visual with the pbiviz toolchain (powerbi-visuals-tools). Covers environment setup, the visual project structure, capabilities.json (data roles, dataView mappings, objects, features, privileges), the IVisual API lifecycle (constructor, update, getFormattingModel, destroy), reading the dataView (categorical, table, matrix, single), the modern format pane and formatting model utils, selection and cross-filtering, tooltips, context menus, drill-down, bookmarks, landing pages, rendering events, local storage, launchUrl, D3 rendering, unit testing, ESLint, packaging to a .pbiviz file, and submitting to AppSource / Partner Center for certification. Example user requests: "create a custom Power BI visual", "build a bar chart visual with pbiviz", "add a format pane card to my visual", "make my visual cross-filter other visuals", "why is my visual data view empty", "get my Power BI visual cert4---56# Power BI Custom Visuals Development78Custom Power BI visuals are web components — written in TypeScript, rendered with D3/SVG/Canvas/HTML, and packaged as a single `.pbiviz` file — that run sandboxed inside an `iframe` in Power BI Desktop and the Power BI service. You build them with the **pbiviz** command-line tool (the `powerbi-visuals-tools` npm package) against the typed **`powerbi-visuals-api`**. This skill covers the full lifecycle: scaffold → develop → debug → package → certify.910> This is a knowledge plugin. It generates and reviews source files (`visual.ts`, `capabilities.json`, `settings.ts`, `pbiviz.json`) and drives the local `pbiviz` CLI — it does not require any MCP server or cloud credentials.1112## Prerequisites1314- **Node.js** (current LTS) and **npm**. Install the toolchain globally: `npm i -g powerbi-visuals-tools@latest` (provides the `pbiviz` command).15- A **Power BI Pro** or **Premium Per User (PPU)** account to test in the service, plus an IDE (VS Code recommended).16- **Developer mode** enabled — in Power BI Desktop (*File ▸ Options ▸ Report settings ▸ Develop a visual*, per session) or in the service (*Developer settings ▸ Power BI Developer mode*). See `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/environment-setup.md`.17- For certification: a **Partner Center** account and a public/reviewable **GitHub** repository.1819## Choosing how to build2021The `pbiviz` SDK is the most powerful path, but not always the right one. Pick the lightest approach that meets the need: **SVG rendered from a DAX measure** (inline sparklines/KPIs in tables, no visual to build), **Deneb** (declarative Vega/Vega-Lite, certified), the **HTML Content** visual, **Charticulator** (no-code), or the full **pbiviz SDK** (TypeScript + D3/React) when you need lifecycle control, a custom format pane, advanced interactivity, or AppSource distribution. The full decision guide and low-code patterns are in `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/building-approaches.md`. The rest of this skill covers the SDK path in depth.2223## Deneb — declarative Vega / Vega-Lite (the no-build path)2425[Deneb](https://deneb.guide) is a **certified** custom visual that runs **Vega** and **Vega-Lite** JSON specs inside Power BI — no `pbiviz` toolchain, no build, yet with native cross-filtering, tooltips, context menus, and report-theme colors. Reach for it when the chart exists in the Vega ecosystem but not the Power BI core set and the user wants a certified result fast. Key facts:2627- **Bind data via the named dataset `dataset`** — `{ "data": { "name": "dataset" } }` (Vega-Lite) or a `dataset` data source (Vega). Field names are the column **display names** from Deneb's *Values* well.28- **Provider:** Vega-Lite (concise `mark`+`encoding`, parameters) for standard charts; Vega (explicit scales/signals/marks) for bespoke layouts and manual interactivity.29- **Cross-filtering:** enable it in Settings, then style on the injected **`__selected__`** field (`'on'`/`'off'`/`'neutral'`). Advanced (Vega-only) mode uses the `pbiCrossFilterSelection` signal with **`pbiCrossFilterApply(event, filter?, options?)`** / **`pbiCrossFilterClear()`** for brush/aggregate selection.30- **Deneb expression functions:** **`pbiColor(index, shade?)`** (theme colors), **`pbiFormat(value, fmt, opts?)`** (Power BI format strings + locale), **`pbiPatternSVG(pattern, fg, bg)`** (texture fills, SVG mode).31- **Responsive:** `"width": "container"`, `"height": "container"`, `"autosize": { "type": "fit", "contains": "padding" }`. Keep shared styling in the **Config** object; reuse charts via the **template** (`usermeta`) system.32- **Certified-build limits:** no external `data.url`, remote images, or external fonts — all data flows through `dataset`.3334Run `/pbiviz-deneb` to author or iterate a spec. Full reference: `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/deneb-vega.md`; copy-paste specs: `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/deneb-specs.md`.3536## The visual lifecycle at a glance3738| Stage | Command / artifact | Reference |39|-------|--------------------|-----------|40| Set up environment | `npm i -g powerbi-visuals-tools@latest`, enable dev mode | `references/environment-setup.md` |41| Scaffold a project | `pbiviz new <name>` | `references/project-structure.md` |42| Declare data + format contract | `capabilities.json` | `references/capabilities.md` |43| Shape the incoming data | `dataViewMappings` + parse `options.dataViews[0]` | `references/dataview-mapping.md` |44| Render & handle lifecycle | `IVisual` class in `src/visual.ts` | `references/visual-api.md` |45| Build the Format pane | `getFormattingModel` + formatting model utils | `references/formatting-model.md` |46| Add interactivity | selection, tooltips, context menu, drill, bookmarks | `references/interactivity.md` |47| Live debug | `pbiviz start` + Developer Visual | command `/pbiviz-debug` |48| Test & lint | ESLint + jasmine/karma unit tests | `references/testing.md` |49| Package | `pbiviz package` → `dist/<name>.pbiviz` | `references/packaging-certification.md` |50| Certify & publish | Partner Center + AppSource | `references/packaging-certification.md` |5152## Project structure5354`pbiviz new <name>` scaffolds a complete project. The files that matter most:5556- **`pbiviz.json`** — visual metadata: internal `name`, `displayName`, unique `guid`, `visualClassName` (must match your `IVisual` class name), `version` (four-part `x.x.x.x`), `apiVersion`, `author`, `assets.icon`, and the paths to `capabilities.json` and `style/visual.less`.57- **`capabilities.json`** — the contract with the host: what data the visual accepts and what appears in the Format pane.58- **`src/visual.ts`** — the `IVisual` implementation (your render code).59- **`src/settings.ts`** — the formatting settings model (Format pane cards/slices).60- **`style/visual.less`** — styles.61- **`assets/icon.png`** — the Visualizations-pane icon, a **20×20 PNG**.62- **`tsconfig.json`**, **`package.json`**, **`package-lock.json`**, **`.eslintrc`**.6364Full annotated layout and `pbiviz.json` field reference: `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/project-structure.md`.6566## capabilities.json — the data and format contract6768`capabilities.json` tells the host what kind of data the visual accepts and what customizable properties appear in the Format pane. From **API v4.6.0** all root properties are optional **except `privileges`, which is required** (use `"privileges": []` when the visual needs no special access).6970Root objects:7172- **`privileges`** — special access the visual needs: `WebAccess` (external URLs — **must be empty for certification**), `ExportContent` (download to file), `LocalStorage`.73- **`dataRoles`** — the field wells users drag data into. Each has a `name`, `displayName`, and `kind`: `Grouping` (discrete buckets), `Measure` (numeric), or `GroupingOrMeasure`.74- **`dataViewMappings`** — how roles map into a `DataView` (`categorical`, `table`, `matrix`, or `single`), with `conditions` bounding how many fields each role accepts and a `dataReductionAlgorithm` (`top`/`bottom`/`sample`/`window`, default `top` at 1000, max 30000).75- **`objects`** — Format pane properties. Each object/property name must exactly match a card/slice in your formatting model.76- **Feature flags** — `supportsHighlight`, `sorting`, `drilldown`, `expandCollapse`, `supportsLandingPage`, `supportsEmptyDataView`, `supportsKeyboardFocus`, `tooltips`, `advancedEditModeSupport`, `supportsMultiVisualSelection`, `subtotals`, `keepAllMetadataColumns`.7778Details and copy-paste blocks: `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/capabilities.md`. Complete files: `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/capabilities-json.md`.7980## DataView — reading the data8182Each valid `dataViewMappings` entry produces a `DataView` delivered in `update(options)` as `options.dataViews[0]`. Power BI only populates the mapping types you declared.8384- **`single`** — one aggregated value (`dataView.single.value`). For KPI cards.85- **`categorical`** — independent groupings + measures (`dataView.categorical.categories[]` and `.values[]`). The most common mapping for charts. Group `values` `by` a series role for hierarchical/series data; read groups with `categorical.values.grouped()`.86- **`table`** — a flat list of rows (`dataView.table.columns[]`, `dataView.table.rows[]`). **Do not assume row order.**87- **`matrix`** — hierarchical rows/columns as a tree of `DataViewMatrixNode` (`dataView.matrix.rows.root`, `.columns.root`, `.valueSources`). Supports expand/collapse of row headers (API 4.1+).8889Always null-check the mapping (`if (!dataView?.categorical?.values) return;`) before reading — a user may not have populated every field well. Parsing patterns for every mapping type: `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/dataview-mapping.md`.9091## The IVisual API9293Every visual is a class implementing `IVisual` (named exactly as `visualClassName` in `pbiviz.json`):9495```typescript96export class Visual implements IVisual {97 constructor(options: VisualConstructorOptions) { /* one-time setup */ }98 public update(options: VisualUpdateOptions): void { /* render on every data/size/view change */ }99 public getFormattingModel(): powerbi.visuals.FormattingModel { /* build the Format pane */ }100 public destroy(): void { /* optional cleanup */ }101}102```103104- **`constructor(options)`** — runs once. Capture `options.element` (your DOM root) and `options.host` (the `IVisualHost`), and create long-lived services (`createSelectionManager`, `createLocalizationManager`, `colorPalette`, `tooltipService`, `eventService`).105- **`update(options)`** — runs on every change. `options.viewport` is the size, `options.dataViews` the data, `options.type` flags the cause (`Data | Resize | ViewMode | Style | ResizeEnd`). Re-render here.106- **`getFormattingModel()`** — returns the Format pane model (replaces the deprecated `enumerateObjectInstances`).107108Host services (selection, tooltips, color palette, `launchUrl`, `persistProperties`, `fetchMoreData`, `storageService`, `eventService`, `displayWarningIcon`, `acquireAADTokenService`) are detailed in `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/visual-api.md`.109110**Rendering Events API (required for certification):** call `host.eventService.renderingStarted(options)` at the start of `update`, `renderingFinished(options)` when the DOM is fully drawn, and `renderingFailed(options, reason)` on error. This signals "export to PDF/PowerPoint" and automated tests that rendering is complete.111112## The modern Format pane (API 5.1+)113114Use API version **5.1 or later** and implement `getFormattingModel`. The recommended approach is the **formatting model utils** (`powerbi-visuals-utils-formattingmodel`):1151161. Declare a settings model in `src/settings.ts` extending `formattingSettings.Model`, composed of **cards** (`formattingSettings.SimpleCard` / `CompositeCard`) → optional **groups** → **slices** (`ToggleSwitch`, `NumUpDown`, `Slider`, `ColorPicker`, `ItemDropdown`, `AutoDropdown`, `FontControl`, `TextInput`, `AlignmentGroup`, …). **Card `name` must equal the object name and slice `name` must equal the property name in `capabilities.json`.**1172. In the constructor: `this.formattingSettingsService = new FormattingSettingsService(localizationManager?)`.1183. In `update`: `this.settings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);`1194. Implement `getFormattingModel()` → `return this.formattingSettingsService.buildFormattingModel(this.settings);`120121Property type ↔ capabilities value-type mapping, composite slices, conditional formatting (per-data-point colors via `dataViewWildcard` selectors + `instanceKind`), and reset-to-default: `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/formatting-model.md`. Full `settings.ts`: `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/formatting-settings.md`.122123## Interactivity124125- **Selection & cross-filtering** — create an `ISelectionManager` in the constructor and an `ISelectionId` per data point with `host.createSelectionIdBuilder().withCategory(...)` / `.withSeries(...)` / `.withTable(...)` / `.withMatrixNode(...)`. Call `selectionManager.select(id, multiSelect)` on click; reflect `selectionManager.getSelectionIds()` visually. Support Ctrl-click for multi-select.126- **Highlighting** — set `"supportsHighlight": true` and render the `values[i].highlights` array (non-highlighted portions dimmed) when other visuals cross-filter yours.127- **Tooltips** — declare `"tooltips"` in capabilities and use `host.tooltipService` (or `powerbi-visuals-utils-tooltiputils`) to show/move/hide tooltips on pointer events.128- **Context menu** — `selectionManager.showContextMenu(selectionId, {x, y}, dataRole?)` on `contextmenu`. The `dataRole` argument is required when the visual supports `drilldown` or `expandCollapse`.129- **Drill-down / expand-collapse**, **bookmarks** (register a selection callback, restore on `update`), **landing page** (`supportsLandingPage` + `supportsEmptyDataView`), **`launchUrl`**, **local storage**, and the **color palette** are all covered in `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/interactivity.md`.130131## Testing, linting, and security132133Certification requires `eslint`, `eslint-plugin-powerbi-visuals`, and `typescript` in `package.json`, a clean `npm audit` (no high/moderate), and no JS console errors. Unit tests use jasmine + karma with `powerbi-visuals-utils-testutils`. Manipulate the DOM safely — **never** use `innerHTML`/`D3.html()` with user data, and avoid `eval`/`Function`/dynamic `setTimeout`. See `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/testing.md`.134135## Packaging & certification136137- **Package:** `pbiviz package` writes `dist/<name>.pbiviz`. The `description` field in `pbiviz.json` must be filled in or the command fails. Bump the four-part `version` before each package.138- **Certify:** publish to AppSource via **Partner Center**, then optionally request certification. Requirements: latest API, a lowercase **`certification`** Git branch matching the submitted package, OSS-only libraries, Rendering Events API support, **no external network access** (`WebAccess` empty/omitted), no minified code, and a clean `pbiviz package --certification-audit`. Full checklist: `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/packaging-certification.md`.139140## Utility packages141142Microsoft ships helper packages so you don't reinvent common chart plumbing: `powerbi-visuals-utils-formattingmodel` (Format pane), `-dataviewutils`, `-formattingutils` (number/date formatting + text measurement), `-svgutils`, `-chartutils` (axes/legend), `-colorutils`, `-interactivityutils`, `-tooltiputils`, `-typeutils`, and `-testutils`. Reference + common errors: `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/utils-and-troubleshooting.md`.143144## Reference files145146| File | Path | Content |147|------|------|---------|148| Building approaches | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/building-approaches.md` | Choosing SDK vs Deneb vs SVG-via-DAX vs HTML Content vs Charticulator; React + pbiviz MCP |149| Deneb (Vega/Vega-Lite) | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/deneb-vega.md` | Deneb editor, `dataset` binding, cross-filter (`__selected__`, `pbiCrossFilterApply`), `pbiColor`/`pbiFormat`/`pbiPatternSVG`, themes, templates, certified limits |150| Environment setup | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/environment-setup.md` | Node, pbiviz install, dev mode, account/SSL setup |151| Project structure | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/project-structure.md` | Folder layout, `pbiviz.json`, `tsconfig`, `package.json` |152| Capabilities | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/capabilities.md` | privileges, dataRoles, mappings, objects, feature flags |153| DataView mapping | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/dataview-mapping.md` | single/categorical/table/matrix parsing, reduction, conditions |154| Visual API | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/visual-api.md` | IVisual lifecycle, host services, rendering events |155| Formatting model | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/formatting-model.md` | Format pane, utils, slice types, conditional formatting |156| Interactivity | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/interactivity.md` | selection, tooltips, context menu, drill, bookmarks, landing page |157| Testing | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/testing.md` | ESLint, unit tests, debugging, security rules |158| Packaging & certification | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/packaging-certification.md` | pbiviz package, AppSource, certification checklist |159| Utils & troubleshooting | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/references/utils-and-troubleshooting.md` | utility packages, common errors and fixes |160161## Example files162163| File | Path | Content |164|------|------|---------|165| Visual (bar chart) | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/visual-ts-barchart.md` | Complete `visual.ts`: IVisual, D3, selection, tooltips, rendering events |166| capabilities.json | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/capabilities-json.md` | Complete capabilities for categorical, table, and matrix visuals |167| Formatting settings | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/formatting-settings.md` | `settings.ts` cards/groups/slices + conditional formatting |168| Config files | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/pbiviz-and-config.md` | `pbiviz.json`, `tsconfig.json`, `package.json`, `.eslintrc` |169| Scaffold walkthrough | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/scaffold-walkthrough.md` | End-to-end: new → develop → start → package → certify |170| Deneb specs | `${CLAUDE_PLUGIN_ROOT}/skills/powerbi-custom-visuals/examples/deneb-specs.md` | Copy-paste Vega/Vega-Lite specs: cross-filter bar, rolling-mean line, bullet, pattern fills, advanced-mode Vega, theme config, template `usermeta` |