Skip to content

ADR-012: Apply Vizro best practices for KPI cards and responsive design

Note: This ADR was originally numbered ADR-002 but was renumbered to ADR-012 during the 2026-01-28 namespace consolidation to resolve collision with ADR-002-cross-validation-strategy.md

Status: Approved Date: 2026-01-28 Deciders: @cloud-architect, @product-owner, HITL/Manager

Context

Current ITSM demo has UX issues identified by product-owner:

  1. KPI cards: Basic styling, no reference comparison, inconsistent icons
  2. Instruction text: On homepage instead of contextual tooltip
  3. Table pagination: Missing (infinite scroll causes performance issues with 74+ rows)
  4. Responsive design: Untested at 200% zoom (WCAG 2.1 AA requirement)

We need to align with Vizro best practices and accessibility standards.

Decision

Apply four UX improvements following Vizro design patterns:

1. KPI Card Styling (McKinsey Visual Vocabulary)

Use kpi_card_reference with: - Icons: Material Icons (ticket, priority, calendar, alert) - Reference comparison: Show delta vs target/baseline (e.g., "+5.2% vs. last week") - Layout: vm.Grid(grid=[[0, 1, 2, 3]], col_gap='20px') for responsive spacing - Min height: 120px to prevent text wrapping at 150%+ zoom

Pattern source: call-center/app.py:48-97

2. Contextual Tooltips

Move instruction from homepage text to KPI card header field:

# OLD: Homepage text
"Click any KPI card to filter the dashboard below."

# NEW: Contextual tooltip
vm.Figure(
    header='💡 Click on a KPI card to filter the dashboard below.',
    figure=kpi_card_reference(...)
)

Pattern source: bi-dashboard/app.py:132 (usa_map header example)

3. Table Pagination

Enable default 10 rows per page:

vm.AgGrid(
    figure=dash_ag_grid(
        data_frame=df,
        dashGridOptions={
            'pagination': True,
            'paginationPageSize': 10,
            'paginationAutoPageSize': False
        }
    )
)

Pattern source: kpi-dashboard/app.py:231

4. Responsive Design (25%-200% zoom)

Add viewport meta tag and CSS media queries:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=2.0">
/* 200% zoom */
@media (min-resolution: 192dpi) {
    .kpi-card { font-size: 1.2rem; padding: 16px; }
}

/* 150% zoom */
@media (min-resolution: 144dpi) {
    .kpi-card { padding: 12px; }
}

/* 50% zoom */
@media (max-resolution: 48dpi) {
    .kpi-card { min-width: 200px; }
}

Test at 5 zoom levels: 25%, 50%, 100%, 150%, 200%

Consequences

Positive

  • WCAG 2.1 AA compliant: 200% zoom requirement met (accessibility)
  • Reduced cognitive load: Tooltip shows instruction in context (UX best practice)
  • Better data navigation: Pagination prevents scroll fatigue with 74+ rows
  • Consistent design system: Aligns with McKinsey Vizro Visual Vocabulary
  • Performance: Pagination reduces DOM nodes from 74 to 10 (7.4x improvement)

Negative

  • CSS complexity: Media queries add 15 LOC of styling code
  • Testing overhead: Must validate 5 zoom levels (adds ~5min to E2E tests)
  • Viewport constraint: maximum-scale=2.0 prevents zoom >200% (intentional tradeoff)

Risks

  • Risk 1 (Text overflow at 200% zoom): Probability MEDIUM, Impact LOW
  • Mitigation: Playwright E2E screenshots at 200% zoom, CSS text-overflow: ellipsis

  • Risk 2 (Pagination breaks filter): Probability LOW, Impact MEDIUM

  • Mitigation: Tier 3 E2E test validates "filter + pagination" interaction

Alternatives Considered

  1. Use Dash Bootstrap Components: Rejected because Vizro native components provide better theme consistency
  2. Disable zoom >150%: Rejected because WCAG 2.1 AA requires 200% support
  3. Client-side pagination only: Rejected because server-side pagination needed for 1000+ rows (future-proofing)

References

Evidence

  • Responsive validation: tmp/cloud-infrastructure/evidence/responsive-validation-{zoom}pct.png (5 screenshots)
  • Playwright test: tests/e2e/test_itsm_responsive.spec.py
  • CSS source: dashboards/itsm/shared/responsive.css