visual-interactivity
Skill29 starsChanged 10 days agoMITView on GitHub
Implements visual selections and coordinated visual behavior. Covers Vega-Lite native selections, VegaVisual and DataGrid interaction events, cross-filtering, cross-highlighting, filter-aware grid totals, and parameterized query factories for runtime visual state.
In this repository7 other files it gives its agents.
- AGENTS.mdAGENTS.md
- app-designSkill
- dax-authoringSkill
- query-designSkill
- schema-querySkill
- semantic-model-dataSkill
- visualsSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 5 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 12
Use this skill to implement visual selections and coordinated behavior.
- Distinctive: line 28
Prefer native Vega-Lite behavior for styling that is entirely local to one chart.
- Distinctive: line 78
When writing the configuration for a template page:
- Very specific: line 83
Use kind: "visual" for charts, "grid" for DataGrid, and "slicer" for slicers.
- Very specific: line 130
Read Query factories. Accept ManagedQueryFactoryParams in each target's query factory and load it with useQueryFactoryTarget.
- Distinctive: line 132
Keep showing the previous result while a replacement query is loading.
- Distinctive: line 133
Verify repeated selection, deselection, empty results, and query failures.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Visual Interactivity
Use this skill to implement visual selections and coordinated behavior. Visual components emit selections and render the tables they receive. For report interactions, an InteractionManager from @microsoft/fabric-interaction-manager owns the selection state and compiles it into DAX filters for the other visuals' queries.
Choose the implementation
This file covers manager configuration, source binding, and target capabilities. Read a reference only when the page needs it:
| Behavior | Read |
| Highlight or dim marks inside one chart | Native selections |
| Coordinate the visuals, grids, and slicers on a page | Interaction Manager below, then Query factories for every target's filter insertion and loading |
| Cross-highlight a bar, column, pie, or donut target | Highlight queries |
| Filter a measures-only, columns-only, multiple-base, or Top N query, or one with an outer filter context | Advanced query shapes |
| Keep a provided DataGrid total aligned with local filters, including a managed grid | Filter-aware grid totals |
| Change DAX or a spec from other runtime state | Query factories |
| Publish predicates from a custom control | The package README: sets, ranges, BLANK, dates, text |
Prefer native Vega-Lite behavior for styling that is entirely local to one chart. Route selections that affect other visuals through the Interaction Manager.
The API surface below and the references' examples cover every export a template page needs, so do not search the package's .d.ts files.
API surface
// Root entry: no React dependency.
import {
InteractionManager, // new InteractionManager(configuration: InteractionConfiguration)
createHighlightData, // (all, highlightedSubset, groupingFields: readonly string[], missingMeasureReplacementValues: Record<string, number | null>, plottedMeasureFields: readonly string[]) => { all: DataTable; highlighted: DataTable }
} from "@microsoft/fabric-interaction-manager";
import type {
InteractionConfiguration, // { semanticModelId: string; fields: Record<string, InteractionField>; components: Record<string, InteractionComponent>; rules?: InteractionRule[] }
InteractionField, // { table: string; column: string; dataType: "string" | "number" | "boolean" | "date" | "datetime" }
InteractionComponent, // { kind?: "visual" | "grid" | "slicer" | "custom"; selectableFields?: string[]; sourceEffect?: "filter" | "auto"; canFilter?: boolean; canHighlight?: boolean; receivesInteractionsByDefault?: boolean }
InteractionRule, // { sourceId: string; targetId: string; targetEffect: "filter" | "highlight" | "none" }
ManagedQueryFactoryParams, // { interactionFilters?: readonly string[] }
InteractionTargetLoadContext,// { isCrossHighlightActive: boolean; compiledFilters: CompiledDaxFilters }
CompiledDaxFilters, // getFilters(mode: "baseline" | "highlight"): readonly string[]
InteractionTargetData, // DataTable | { all: DataTable; highlighted: DataTable }
ManagedTargetLoadState, // loading | refreshing | ready | refresh-error (retained data + error) | error (no data)
ManagedInteractionSource, // { selections; selectableFields; onInteraction; error?: Error }
} from "@microsoft/fabric-interaction-manager";
// React entry.
import {
InteractionManagerProvider, // <InteractionManagerProvider manager={manager}>
useManagedInteractionSource, // (sourceId: string) => ManagedInteractionSource
useManagedInteractionTarget, // (targetId: string, loader: (context: InteractionTargetLoadContext) => Promise<InteractionTargetData>) => ManagedTargetLoadState
useInteractionManager, // () => InteractionManager; call .clearAll() to reset every source
} from "@microsoft/fabric-interaction-manager/react";
// Template helpers.
import { useQueryFactoryTarget } from "@/hooks/use-query-factory-target";
// useQueryFactoryTarget(targetId, factory, params, highlightAlignment?: HighlightAlignment) => QueryFactoryTargetState
// data is DataTable, or { all, highlighted } with highlightAlignment: { groupingFields; missingMeasureReplacementValues; plottedMeasureFields }
import { executeQueryFactory, insertInteractionFilters } from "@/lib/query-factory";
// executeQueryFactory(factory: { connection, query, columnMetadata }, bypassCache = false): Promise<DataTable>; for custom loaders
// insertInteractionFilters(query, filters, marker, position: "beforeMeasures" | "afterTable"): stringSelection types (SemanticSelection, InteractionPredicate, InteractionValue, RangeBoundary) and isDataTable come from @microsoft/fabric-visuals-core.
Interaction Manager
Configure the manager
Configure one InteractionManager per interaction boundary, at the nearest common host of the coordinated components, and wrap that part of the page in InteractionManagerProvider. Create it once with useState(() => new InteractionManager(configuration)); configuration is fixed for the manager's lifetime. The package README's Configure a manager section lists each component kind's defaults and pair overrides through rules; read it only when the page needs to change those defaults.
When writing the configuration for a template page:
- Set
semanticModelIdto the one semantic model whose fields this manager configures. - Key
fieldsby the bracket-free column aliases in query results, and map each to its model table, column, and data type. - List each source's
selectableFieldsexplicitly; an omitted list means every configured field. Keep those columns, with their raw model values rather than formatted labels, in the source's data even when hidden. - Use
kind: "visual"for charts,"grid"forDataGrid, and"slicer"for slicers. SetcanHighlighton each visual as described in Coordinated visuals.
Bind sources
Bind each component that has selectable model-field identities as a source. Charts and grids that receive interactions are sources too; slicers and custom controls add sources rather than replacing them:
const source = useManagedInteractionSource("salesChart");
<VegaVisual spec={vegaLiteSpec} data={result.data} theme={theme}
isCrossHighlightActive={result.isCrossHighlightActive}
selections={source.selections} selectableFields={source.selectableFields}
onInteraction={source.onInteraction} />
{source.error && <div role="alert">{source.error.message}</div>}DataGridtakes the same source props. Controlled chart selection requires a Vega-Lite spec.- Each click publishes the component's complete selection. When the manager rejects a selection, it sets
source.errorand keeps the previously accepted selection. - The manager owns accepted selections. Do not mirror them into component state.
- Slicers only report selections: pass
source.onInteractionand rendersource.error. Slicers that report interactions reject JavaScriptDatevalues, so pass dates as the strings the model returns. - Clear one source by passing
[{ action: "clear" }]to itsonInteraction, or every source withuseInteractionManager().clearAll(). Controlled components update without raising selection events.
Load every component that receives interactions with useQueryFactoryTarget; see Query factories. A shared chart or grid wrapper binds both hooks and passes the source props; render target-only components through a separate path.
A component is target-only when its rows have no selectable identities, such as a measures-only grid, or when the user asks for it. Register it with selectableFields: [], load it as a target, and render it without source props as shown in Query factories.
Coordinated visuals
- Cross-filtering re-evaluates the target under the manager's compiled DAX filters. Do not filter pre-aggregated results in the browser; it cannot recalculate distinct counts, ratios, totals, or selections on unprojected columns. See Query factories.
- Cross-highlighting keeps the full baseline visible, dimmed, and draws the selected subset bright on top. Re-aggregate the subset at the baseline's grouping, measures, and row set rather than filtering an already aggregated baseline table. See Highlight queries.
- Local presentation filters, such as a search box over loaded grid rows or a Vega-Lite filter inside one unmanaged visual, only restrict displayed rows and can run in the browser. Label any subtotal over locally filtered rows accordingly.
Choose each visual target's canHighlight from its mark type and measures:
| Visual | Target configuration |
| Bar and column, including stacked and clustered | Cross-highlight with a highlight alignment; pass the spec unchanged |
| Pie and donut | Cross-highlight when the measures are non-negative and additive; otherwise canHighlight: false |
| Line and scatter | canHighlight: false; they receive cross-filters |
| Other shapes and layered combinations | canHighlight: false unless the target draws its own layers from named data; see Highlight queries |
Implement the manager configuration and highlight alignment together. createHighlightData falls back to showing the highlighted values as the main values when they cannot be drawn as a part of the baseline, so wire highlighting by visual type without checking each source's relationships or measure definitions.
Implementation workflow
- Identify the sources, targets, and each target's behavior from Coordinated visuals.
- Discover the model fields, then register fields and components in one
InteractionManagerat the nearest common host of the coordinated visuals. - Read Query factories. Accept
ManagedQueryFactoryParamsin each target's query factory and load it withuseQueryFactoryTarget. Before loading a bar, column, pie, or donut target, read Highlight queries; for other query shapes, use the table in Choose the implementation. - Bind every source with
useManagedInteractionSourceand pass its props to the rendered component. - Keep showing the previous result while a replacement query is loading.
- Verify repeated selection, deselection, empty results, and query failures.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

