Agent Skills: Wiring Vizro Actions

Use this skill when adding cross-filter, cross-highlight, drill-through, or data export interactions to a Vizro dashboard — both for choosing the right interaction pattern during design and for implementing actions in code. Activate when the user wants clicks on a chart or table to filter or highlight other charts, tables, or figures, needs cross-page navigation with pre-set filters, or wants users to download data.

UncategorizedID: mckinsey/vizro/wiring-vizro-actions

Repository

mckinseyLicense: Apache-2.0
3,810305

Install this agent skill to your local

pnpm dlx add-skill https://github.com/mckinsey/vizro/tree/HEAD/vizro-e2e-flow/skills/wiring-vizro-actions

Skill Files

Browse the full folder contents for wiring-vizro-actions.

Download Skill

Loading file tree…

vizro-e2e-flow/skills/wiring-vizro-actions/SKILL.md

Skill Metadata

Name
wiring-vizro-actions
Description
Use this skill when adding cross-filter, cross-highlight, drill-through, or data export interactions to a Vizro dashboard — both for choosing the right interaction pattern during design and for implementing actions in code. Activate when the user wants clicks on a chart or table to filter or highlight other charts, tables, or figures, needs cross-page navigation with pre-set filters, or wants users to download data.

Wiring Vizro Actions

Core concept: Source → Control → Target

All advanced interactions follow the same shape:

  1. A source component triggers va.set_controls when the user clicks it. Practical sources are vm.Graph and vm.Table — they carry click-data (column values from the clicked point/cell) that can drive a dynamic filter. (vm.Figure/vm.Button/vm.Card technically support set_controls too, but only with a hardcoded literal value, so they are not useful for cross-filtering.)
  2. set_controls writes a value into an intermediate control (vm.Filter or vm.Parameter) with an explicit id.
  3. The control updates target components. Filter/Parameter targets are data-bearing components: vm.Graph, vm.Table, vm.Figure, vm.Table.

The control is always explicit — you do not connect components directly. This makes interactions composable (you can wire multiple sources to the same control, or one source to multiple controls).

Built-in actions

| Action | Purpose | Trigger | | --- | --- | --- | | va.export_data() | Download all on-page data as CSV (respects filters) | vm.Button | | va.set_controls(controls=..., value=...) | Set the value of a Filter or Parameter | vm.Graph or vm.Table |

import vizro.actions as va. Built-in actions are passed directly into actions= — wrapping them in vm.Action raises an error (deliberate: built-ins have their own predefined inputs/outputs and would conflict with vm.Action's).

# Correct
vm.Button(text="Export data", actions=va.export_data())
vm.Graph(actions=va.set_controls(controls="region_filter", value="y"))

# Wrong — raises an exception
vm.Graph(actions=[vm.Action(function=va.set_controls(...))])

Named interaction patterns

Match data shape + user need to a pattern. Full details (when-to-use, wireframes, spec entries, code) in actions-reference.md.

| # | Pattern | When to use | Key mechanic | | --- | --- | --- | --- | | 1 | Hierarchical Drill-Down (cross-page) | 2–3 level hierarchy where detail needs a dedicated page | cross-filter + show_in_url=True + back button + export | | 2 | Single-Page Drill-Down (container) | 2-level hierarchy where detail fits in a container | cross-filter into a container | | 3 | Comparison Spotlight (cross-highlight) | Compare one entity against many without removing context | custom chart with highlight_X + invisible Parameter | | 4 | Multi-Dimensional Slice | 2+ categorical dimensions (e.g. day × time heatmap) | actions chain → multiple Filters | | 5 | Data Export | Analyst persona needs the filtered data downloaded | vm.Button + va.export_data() |

Decision flow (pick at most one of Patterns 1–4 as the primary interaction, then independently add Pattern 5 if export is needed):

Does the data have a natural hierarchy (group → individual → detail)?
├─ YES, detail needs its own page → Pattern 1
├─ YES, detail fits in a container → Pattern 2
└─ NO → continue

Compare one entity against many without removing context?
├─ YES → Pattern 3
└─ NO → continue

2+ categorical dimensions, click to drill into one cell?
├─ YES → Pattern 4
└─ NO → A standard sidebar vm.Filter is sufficient — no advanced pattern needed.

Then independently: does the user need to download data?
├─ YES → add Pattern 5 (Data Export button) on top of whichever pattern you chose above (or on its own)
└─ NO → done

When NOT to use advanced interactions

Use a chart or table as a Filter/Parameter source only when the user explicitly asks for it, or when a pattern's "When to use" clause clearly matches. The bullets below are common cases where the sidebar wins.

  • View-only dashboards (executive summary — users glance, not explore)
  • Simple filtering needs (a sidebar dropdown covers it)
  • Small datasets (< ~5 groups — a filter is simpler and clearer)
  • More than 2 interaction patterns per page (becomes confusing)

Key gotchas

  • custom_data for non-positional values: When cross-filtering from a graph using a column that is not on a positional axis (x/y/z/lat/lon), add custom_data="column" to the figure and use value="column" in set_controls. Otherwise the click does nothing.
  • visible=False for cross-highlight: When a Parameter is the highlight control, hide its selector — the highlight effect itself is the feedback. Also set visible=False on a cross-filter when the user explicitly requests it.
  • "NONE" in highlight Parameter selector options: Include "NONE" as the first option so the chart starts unhighlighted.
  • show_in_url=True for cross-page: Required on the target Filter. Without it, Vizro raises ValueError at build time and the app won't start.
  • Back button + Flex layout for drill-through targets: Pages that receive a drill-through must use layout=vm.Flex(direction="column") so the back button takes natural height (Grid would waste a full 140px+ row). Put remaining content in a vm.Container with its own vm.Grid.
  • Header hint on interactive source: Always add a short, action-oriented header (e.g. header="Click a bar to filter by region") so users know the component is clickable.
  • Don't use filter_interaction: It was removed in Vizro 1.0.0. Use va.set_controls instead.

Quick code recipes

Export data (Pattern 5)

vm.Button(text="Export data", actions=va.export_data())

Cross-filter from chart (Pattern 1 or 2)

vm.Graph(
    header="Click a bar to filter by region",
    figure=px.bar("data", x="value", y="region", orientation="h"),
    actions=va.set_controls(controls="region_filter", value="y"),
)
vm.Filter(id="region_filter", column="region")

Actions chain — one click sets multiple controls (Pattern 4)

vm.Graph(
    header="Click a cell to filter the table below",
    figure=px.density_heatmap("appointments", x="day", y="time_slot"),
    actions=[
        va.set_controls(controls="day_filter", value="x"),
        va.set_controls(controls="time_filter", value="y"),
    ],
)
vm.Filter(id="day_filter", column="day", targets=["appointments_table"])
vm.Filter(id="time_filter", column="time_slot", targets=["appointments_table"])

Cross-page drill-through (Pattern 1)

# Source page
vm.Table(
    header="Click a row to view details",
    figure=dash_ag_grid("reps"),
    actions=va.set_controls(controls="rep_filter", value="rep_name"),
)

# Target page
vm.Page(
    title="Rep Detail",
    layout=vm.Flex(direction="column"),
    components=[
        # href: "/" if the source page is the first in Dashboard(pages=[...]);
        # otherwise "/<title-lowercased-with-dashes>" (e.g. "/team-overview").
        vm.Button(text="← Back", href="/", variant="outlined"),
        vm.Container(layout=vm.Grid(...), components=[...]),
    ],
    controls=[vm.Filter(id="rep_filter", column="rep_name", show_in_url=True)],
)

Deep dive

Load actions-reference.md when you need:

| Need | Search for | | --- | --- | | Full pattern template (when/why/code/wireframe/spec) | ## Pattern N | | Highlight-aware custom chart wiring (chart shape + Parameter wiring) | ## Pattern 3 | | Multi-dimensional / actions chain | ## Pattern 4 | | Drill-through layout constraint (Flex/Grid/back button, href slug format) | ## Pattern 1 | | Positional vs custom_data and the @capture("graph") signature gotcha | ## Common Implementation Mistakes | | Full common-mistakes table | ## Common Implementation Mistakes |

Key imports

import vizro.actions as va
import vizro.models as vm
import vizro.plotly.express as px
from vizro.tables import dash_ag_grid
from vizro.models.types import capture