Reference · UX pattern catalogueData visualisation patterns

43 patterns in this category — each with its illustration, what it is, and the fields that matter when you build or review one. Part of the UX pattern catalogue; the raw, agent-readable version is ux-pattern-catalogue/dataviz-patterns.json.

Chart types

Jan Mar May

Line Chart dataviz-001

Plots data points connected by lines to show trends over continuous intervals (time series). The default choice for showing change over time. Use when the x-axis is ordered (dates, sequential steps).

Implementation

shadcn: Chart (Recharts wrapper). Use LineChart with Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend. Tremor: LineChart component. For multiple series, use distinct stroke colors from design tokens.

Accessibility

Provide a data table alternative via a toggle or <details> element. Use aria-label on the chart container describing the trend. Never rely on color alone — add point markers or dashed/solid line styles per series.

A B C D E

Bar Chart dataviz-002

Uses rectangular bars to compare discrete categories. Research shows bar charts are the easiest chart type for users to interpret accurately (NN/G). Vertical for categories, horizontal when labels are long.

Implementation

shadcn: Chart with BarChart, Bar, XAxis, YAxis. Tremor: BarChart. Use horizontal layout when category labels exceed 8 characters. Add value labels on bars for small datasets (<10 bars).

Accessibility

Each bar should be focusable with aria-label including category and value. Provide screen-reader-accessible data table. Minimum bar color contrast of 3:1 against background.

Area Chart dataviz-003

A line chart with the area below filled, emphasizing volume or cumulative totals. Stacked areas show part-to-whole over time. Use when the magnitude matters, not just the trend.

Implementation

shadcn: Chart with AreaChart, Area (stackId for stacking). Tremor: AreaChart with stack prop. Use gradient fills (opacity 0.3 → 0) for depth. Limit to 4 stacked series for readability.

Accessibility

Stacked areas are hard to read for colorblind users — provide a toggle to un-stack. Include data table alternative. Label each area with a visible legend.

42% Revenue

Pie & Donut Chart dataviz-004

Shows part-to-whole relationships as angular slices. Donut variant adds a center metric. Limit to 5-6 slices maximum — research shows users struggle to compare similar angles (NN/G). Always sort by size.

Implementation

shadcn: Chart with PieChart, Pie, Cell. Tremor: DonutChart. Place the primary KPI in donut center. Group small slices (<5%) into "Other". Use direct labels not just legend.

Accessibility

Provide percentage values as direct labels or in tooltip. Include a data table alternative — pie charts are one of the hardest chart types for screen readers. Use patterns (stripes, dots) in addition to color.

Scatter Plot dataviz-005

Plots individual data points on two axes to reveal correlations, clusters, and outliers. Use when exploring relationships between two quantitative variables. NN/G notes position is a preattentive variable — outliers are spotted instantly.

Implementation

Recharts: ScatterChart with Scatter, XAxis, YAxis, ZAxis (for bubble size). Tremor: Not built-in, use Recharts directly. Add reference lines for averages. Use color for a third dimension.

Accessibility

Announce data count and visible pattern ("120 points, positive correlation"). Each point focusable with tooltip showing all dimensions. Provide tabular alternative for precise values.

Mon Wed Fri 9am 12pm 5pm

Heatmap dataviz-006

Uses color intensity on a grid to show magnitude across two categorical dimensions. Common for time-of-day activity, correlation matrices, and geographic density. The eye is drawn to hotspots instantly.

Implementation

Build with a CSS Grid of colored cells or D3.js for complex heatmaps. Use a sequential color scale (e.g., white → blue). Show value on hover. Add a color legend with min/max labels.

Accessibility

Never rely on color alone — show values on hover and in a data table. Use aria-label per cell: "Monday 9am: 42 requests". Provide a high-contrast mode with pattern fills.

Revenue $4.2M +12%

Sparkline dataviz-007

A tiny, word-sized chart (typically a line or bar) embedded inline with text or inside a table cell or KPI card. Invented by Edward Tufte to show trends without axis labels. Shows direction, not precise values.

Implementation

Recharts: LineChart with no axes, grid, or tooltip. Set height to 24-32px. Tremor: SparkChart. Color the line or final point green/red to indicate positive/negative trend.

Accessibility

Add aria-label describing the trend: "Revenue: up 12% over 7 days". Sparklines are decorative context — ensure the actual value is available as text nearby.

73% CPU Usage

Gauge / Radial Chart dataviz-008

A semicircular or circular meter showing a single value against a scale. Best for KPIs with known min/max (CPU usage, goal progress, health scores). Limit to one per card — multiple gauges waste space.

Implementation

Recharts: RadialBarChart or custom SVG arc. Tremor: Not built-in, use custom. Show the numeric value prominently in the center. Color zones: green (good), yellow (warning), red (critical).

Accessibility

Display the numeric value as visible text — the visual arc is supplementary. aria-label="CPU usage: 73%". For color zones, add text labels ("Good", "Warning", "Critical") not just color.

1,000 620 280 42 Visit Sign up Trial Paid

Funnel Chart dataviz-009

Shows progressive reduction through sequential stages (conversion funnels, sales pipelines). Each stage is a trapezoid narrower than the previous. Shows both absolute counts and conversion rates between steps.

Implementation

Recharts: FunnelChart with Funnel, LabelList. Show both the count and percentage drop-off at each stage. Color from dark to light as values decrease. Add connector labels for stage-to-stage conversion.

Accessibility

Label each stage with name, count, and conversion rate. Provide a table alternative showing all stages. aria-label on container: "Conversion funnel: 1000 visitors to 42 purchases".

Sales 42% Eng 24% Marketing 15% Support 12% Other 7%

Treemap dataviz-010

Nested rectangles sized by a quantitative value, showing hierarchical part-to-whole. Good for file system usage, budget allocation, or portfolio composition. Area encoding is less precise than bar length but shows hierarchy well.

Implementation

Recharts: Treemap with customized content renderer. D3.js for complex treemaps with drill-down. Label rectangles directly — legends fail with many categories. Use color for a secondary dimension.

Accessibility

Each rectangle needs aria-label with category and value. Provide breadcrumb navigation for drill-down. Include a flat table view as alternative. Minimum rectangle size for touch targets: 44x44px.

Source Destination

Sankey Diagram dataviz-011

Flow diagram where link width is proportional to flow quantity. Shows how values distribute from source to destination (user journeys, budget flows, energy transfers). Reveals leakage and dominant paths.

Implementation

D3-sankey or Recharts Sankey. Nodes on left/right columns, links as curved paths. Color links by source or destination. Show flow quantity on hover. Limit to 15-20 nodes for readability.

Accessibility

Provide a flow table: Source → Destination → Quantity. Each link focusable with tooltip. aria-label on container summarizing the flow: "User journey: 60% of visitors reach checkout".

Total Revenue $12.4k +23.5% Active Users 2,847 -3.2%

KPI Card dataviz-012

A single large number with label, trend indicator, and optional sparkline. The most common dashboard element. Shows current value, comparison to previous period, and directional arrow. Place the 3-5 most critical KPIs at the top of any dashboard.

Implementation

shadcn: Card with large text for value, Badge for trend. Tremor: Metric component. Include: label, value, delta (absolute or %), trend direction arrow, and optional sparkline.

Accessibility

Structure as a heading + value. Trend direction conveyed via text ("up 12%") not just arrow color. Use aria-live="polite" if the value updates in real-time.

Composition

$4.2k 847 92%

Dashboard Grid Layout dataviz-013

Arrange charts and KPIs in a responsive grid with consistent card sizing. Place the most important metrics in the top-left (F-pattern scanning). Limit to 5-9 visible widgets to prevent cognitive overload (NN/G).

Implementation

CSS Grid with named areas or auto-fill. Use 12-column grid for flexibility. shadcn: Card for each widget. Full-width charts on top, smaller cards in 2-3 column rows below. Gap: 1rem.

Accessibility

Use landmark regions: <main> for the dashboard, headings for each section. Logical tab order should match visual layout (left-to-right, top-to-bottom). Skip links to major sections.

Jan 1 - Mar 31 All teams Updated 2m ago

Dashboard Header with Global Filters dataviz-014

A sticky bar above all dashboard widgets containing date range picker, comparison toggle, and global filters. All charts respond to these shared controls. Prevents per-chart filter confusion.

Implementation

shadcn: DatePickerWithRange + Select/Combobox in a sticky flex bar. Store filter state in URL params. All chart queries include the global date range. Show "Last updated: X" timestamp.

Accessibility

Landmark: <nav aria-label="Dashboard filters">. Date picker accessible via keyboard. Announce filter changes with aria-live. Indicate which charts are affected.

Monthly Revenue Jan - Jun 2025

Chart Card with Header dataviz-015

Each chart wrapped in a card with: title, subtitle/description, optional controls (time range tabs, export), and the chart below. Consistent card structure across all dashboard widgets.

Implementation

shadcn: Card > CardHeader (title + description + action buttons) > CardContent (chart). Tremor: Card with Title. Add DropdownMenu for per-chart actions (export, expand, refresh).

Accessibility

Card title in <h3> or appropriate heading level. Chart container has role="img" with aria-label summarizing the data. Action buttons have descriptive labels.

Overview Revenue Users

Tabbed Dashboard Views dataviz-016

Organize dashboard sections into tabs (Overview, Revenue, Users, Performance) to manage complexity without scrolling. The Overview tab shows the top 5-7 KPIs; detail tabs show full charts.

Implementation

shadcn: Tabs with TabsList, TabsTrigger, TabsContent. Lazy-load chart data per tab to reduce initial page load. Persist active tab in URL params.

Accessibility

Standard tab pattern: role="tablist", role="tab" with aria-selected, role="tabpanel" with aria-labelledby. Arrow keys move between tabs. Tab panel announced on switch.

This month Last month

Comparison Layout dataviz-017

Side-by-side or overlay chart layout for comparing two periods, segments, or scenarios. "This period vs last period" is the most common comparison. Overlay on same axes when scales match; split when they differ.

Implementation

Overlay: two Line/Bar series on one chart with a legend. Side-by-side: two Chart components in a 2-column grid. Use solid for current, dashed for comparison. Tremor: comparison prop on charts.

Accessibility

Legend must clearly distinguish series. aria-label: "Revenue: current month vs previous month". Ensure line styles differ (solid vs dashed) — not just color.

No data yet

Empty Dashboard State dataviz-018

What to show when a dashboard has no data yet — because the user is new, the date range has no activity, or the data source is not connected. Never show blank chart containers.

Implementation

Show illustration + message: "No data for this period" or "Connect your data source to get started". For new users, show sample data with a "This is sample data" banner. Include a CTA.

Accessibility

Empty state message must be in the chart region so screen readers encounter it. Use role="status" or aria-live for dynamic empty states when filters produce no data.

Interaction

Apr: $8,420 +15% vs Mar

Tooltip on Hover dataviz-019

A floating card showing precise values when hovering over a data point or bar. The primary way users read exact values from charts. Show all series values at the hovered x-position for line/area charts.

Implementation

Recharts: Tooltip with custom content renderer. Show formatted values with units. For line charts, use a shared tooltip (one per x-position, all series). Tremor: built-in tooltip.

Accessibility

Tooltip must appear on keyboard focus, not just mouse hover. Use aria-describedby to link data points to tooltip content. Tooltip should not obscure other data.

Crosshair dataviz-020

A vertical (or cross-shaped) reference line following the cursor across the chart, snapping to the nearest data point. Helps users track position and compare values across multiple line series.

Implementation

Recharts: set cursor prop on Tooltip. For custom: overlay an SVG line at mouse x-position, snap to nearest data point. Show a dot on each line at the crosshair intersection.

Accessibility

Crosshair is a visual enhancement — not required for accessibility. Ensure the underlying tooltip provides the same value information via keyboard.

Brush / Range Selection dataviz-021

A draggable range selector below the main chart for zooming into a time window. Shows a miniature overview of the full dataset with handles to select a sub-range. Essential for large time series.

Implementation

Recharts: Brush component below the chart. Show a mini area chart in the brush for context. Sync brush range with the main chart domain. Add reset button to restore full range.

Accessibility

Brush handles must be keyboard-operable (arrow keys to move, Shift+Arrow to resize). Announce the selected range: "Showing Jan 15 to Feb 28". Provide date inputs as alternative.

Click to drill Overview > Q3 > Jul breakdown

Drill-Down dataviz-022

Clicking a chart element navigates to a more detailed view. Click a bar to see its breakdown, click a time period to zoom in. Progressive disclosure for complex data — overview first, details on demand (Shneiderman's mantra).

Implementation

Add onClick to chart elements. Navigate to a detail view or expand the chart in-place. Show breadcrumb for navigation back. Animate the transition for context preservation.

Accessibility

Clickable elements need role="button" or be actual <button> elements. Announce drill-down: "Showing breakdown for Q3 Revenue". Breadcrumb provides keyboard-accessible back navigation.

Revenue Costs

Chart Legend dataviz-023

A labeled key mapping colors/patterns to data series. Place below or to the right of the chart. Interactive legends that toggle series visibility are highly valued by users for multi-series charts.

Implementation

Recharts: Legend with onClick to toggle series visibility. Show hidden series as grayed-out in legend. Tremor: built-in interactive legend. Place below chart on mobile, right on desktop.

Accessibility

Legend items must be keyboard-focusable with toggle via Enter/Space. Announce: "Revenue series hidden" / "Revenue series shown". Use patterns + color, not color alone.

Product launch

Chart Annotations dataviz-024

Labels, arrows, or highlighted regions on a chart marking notable events (product launches, outages, promotions). Give context to data anomalies that users would otherwise investigate manually.

Implementation

Recharts: ReferenceLine, ReferenceArea, ReferenceDot with custom labels. Position annotations at the relevant x/y coordinates. Use a distinct annotation color. Show detail on hover.

Accessibility

Each annotation must have a text label accessible to screen readers. Use aria-label on annotation markers. Include annotations in the data table alternative.

Revenue

Chart Export dataviz-025

Allow users to download chart data as CSV/Excel or the chart image as PNG/SVG. Power users need raw data for their own analysis. Place export button in the chart card header.

Implementation

CSV: serialize chart data array and trigger download. PNG: use html2canvas or svg-to-image on the chart container. Add DropdownMenu with "Download CSV", "Download PNG" options.

Accessibility

Export button needs aria-label="Export chart data". Download should trigger a file save dialog. Announce "Download started" via aria-live for screen reader users.

Accessibility

Month Value Jan $4,200 Feb $5,100 Mar $4,800 Chart Table

Data Table Alternative dataviz-026

Every chart must have an equivalent data table that screen reader users can navigate. This is the single most important accessibility requirement for data visualization. Toggle between chart and table view.

Implementation

Add a "View as table" button/toggle above each chart. Render the same data as a <table> with proper <thead>, <th>, <td>. Use shadcn DataTable for sortable tables. Hide/show with display toggle.

Accessibility

Table must include <caption> describing the data. Use scope="col" and scope="row" on headers. Table must contain all the information the chart conveys, including trends noted in annotations.

Color + Shape Color + Pattern Color + Label

Color-Blind Safe Palettes dataviz-027

Use color palettes distinguishable by users with protanopia, deuteranopia, and tritanopia (8% of men, 0.5% of women). Never rely on red/green distinction alone. Test with a color blindness simulator.

Implementation

Use a vetted palette: blue, orange, teal, purple, pink (avoid pure red+green pairs). Tools: Viz Palette, ColorBrewer. In addition to color, use line patterns (solid, dashed, dotted) and point shapes (circle, square, triangle).

Accessibility

WCAG 1.4.1: Color is not the sole means of conveying information. Every color-coded element needs a secondary differentiator (shape, pattern, label, position). Test with Sim Daltonism or similar.

role="img" aria-label="Line chart showing..."

Chart Container ARIA dataviz-028

The outermost chart wrapper needs role="img" with an aria-label summarizing what the chart shows. This is the first thing a screen reader announces — it should convey the chart type, subject, and key insight.

Implementation

Wrap chart in <figure role="img" aria-label="Line chart showing monthly revenue from Jan to Dec 2025, trending upward 23%">. Add <figcaption> as a visible description.

Accessibility

aria-label should include: chart type, what is measured, time range, and the key insight or trend. Keep under 150 characters. Long descriptions go in aria-describedby linked to a <details> element.

Apr: $845 Tab / Arrow keys

Keyboard-Navigable Data Points dataviz-029

Make individual data points focusable and navigable with arrow keys. On focus, show the tooltip with the point's value. Essential for users who cannot use a mouse to hover over chart elements.

Implementation

Add tabIndex to data point SVG elements. Use arrow keys to move between points. Show tooltip on focus (same as hover). Recharts: use activeDot with custom focus handling.

Accessibility

Each data point: role="listitem" or focusable with aria-label including series name, category, and value. Arrow keys move sequentially through points. Escape exits chart navigation.

Standard High Contrast prefers-contrast: more

High Contrast Mode dataviz-030

A toggle or automatic detection that increases chart contrast: thicker lines, larger labels, stronger fill colors, and pattern fills replacing solid colors. Essential for low-vision users.

Implementation

Detect prefers-contrast: more in CSS. Apply: stroke-width increase (1.5→3), font-size increase, pattern fills via SVG <defs>. Use forced-colors media query for Windows High Contrast.

Accessibility

WCAG 1.4.11: Non-text contrast of 3:1 for chart elements. In high-contrast mode, increase to 4.5:1. Ensure axis labels and tick marks remain visible.

Listen to chart

Sonification dataviz-031

Represent data as sound — pitch maps to value, left-to-right panning maps to time. An experimental but powerful alternative for blind users to perceive trends, outliers, and patterns in charts without vision.

Implementation

Use the Web Audio API or libraries like Highcharts Sonification module. Map y-values to pitch (low → high), x-axis to time. Play on button press. Include play/pause/speed controls.

Accessibility

Provide a "Listen to chart" button. Include controls for playback speed and volume. Announce start and end of sonification. This supplements — does not replace — the data table.

Real time

LIVE

Live-Updating Chart dataviz-032

A chart that receives new data points via WebSocket or SSE and appends them in real-time. Common for monitoring dashboards (server metrics, stock prices, IoT sensors). New points slide in from the right.

Implementation

Use WebSocket or EventSource for data stream. Append to chart data array, remove oldest point to maintain a fixed window. Use requestAnimationFrame for smooth animation. Limit update frequency to 1-2 Hz for readability.

Accessibility

Do not announce every data update — it would overwhelm screen readers. Announce only threshold crossings: "CPU usage exceeded 90%". Provide a "Pause updates" button.

Critical Warning

Threshold Alerts dataviz-033

Horizontal reference lines on charts indicating warning and critical thresholds. When values cross a threshold, visually highlight the violation with color change and optional animation. Essential for monitoring dashboards.

Implementation

Recharts: ReferenceLine with label at y-threshold. Color the area above/below threshold with ReferenceArea. Change line/bar color when value exceeds threshold. Add pulse animation on breach.

Accessibility

Announce threshold crossings via aria-live="assertive": "Alert: Response time exceeded 500ms threshold". Threshold lines must be labeled with text, not just color.

Updated 15s ago

Auto-Refresh with Indicator dataviz-034

Dashboard data refreshes on a timer (every 30s, 1m, 5m) with a visible countdown or "last updated" timestamp. Users must know when data is stale. Provide manual refresh and auto-refresh toggle.

Implementation

Use setInterval or React Query refetchInterval. Show "Updated 30s ago" with a countdown ring or progress bar. Add refresh button (Lucide: RefreshCw icon). Store preference in localStorage.

Accessibility

Do not auto-refresh so frequently it disrupts screen reader users (minimum 30s). "Last updated" must be in an aria-live="polite" region. Provide a way to pause auto-refresh.

Stream Buffer batch Render

Streaming Data Buffer dataviz-035

Buffer incoming data points and render in batches to prevent jank from high-frequency updates. If data arrives at 100 Hz, batch into 1-2 Hz visual updates. Preserves all data for analysis while keeping the UI smooth.

Implementation

Collect incoming events in an array. On each animation frame (or setInterval at 500ms), flush buffer to chart state. Use Web Worker for heavy aggregation. Show a "live" indicator dot that pulses.

Accessibility

No specific ARIA requirements — buffering is a performance optimization. Ensure the "live" indicator has aria-label="Receiving live data" for screen readers.

1h 6h 24h 7d Custom

Time Window Selector dataviz-036

Quick-select buttons for common time ranges: "1h", "6h", "24h", "7d", "30d", "Custom". The primary navigation for time-series dashboards. Active range highlighted. Affects all charts on the dashboard.

Implementation

shadcn: ToggleGroup with time range options. "Custom" opens DatePickerWithRange. Store in URL params for shareability. Highlight active option. Place in dashboard header for global scope.

Accessibility

role="radiogroup" with aria-label="Time range". Each option: role="radio" with aria-checked. Announce selection: "Showing last 24 hours".

Metric Value Trend Revenue $4.2M Users 2,847 Uptime 99.9%

Sparkline in Table Cell dataviz-037

Tiny inline charts inside data table cells showing the trend for each row's metric. Combines tabular precision with visual trend context. Common in financial dashboards, server monitoring, and analytics tables.

Implementation

Recharts: minimal LineChart (no axes, no tooltip) sized to 80x24px inside a <td>. Color: green for uptrend, red for downtrend. Pair with the numeric value in an adjacent cell.

Accessibility

The sparkline is decorative — the adjacent cell contains the readable value. Add aria-hidden="true" on the sparkline. Use aria-label on the cell if the trend direction is meaningful: "Revenue: $4.2M, trending up".

Responsive

width: 100%

Responsive Chart Container dataviz-038

Charts must resize fluidly with their container. Use a responsive wrapper that recalculates dimensions on resize. Never set fixed pixel widths on charts — they will overflow or leave whitespace on different screens.

Implementation

Recharts: ResponsiveContainer (width="100%" height={300}). Tremor: responsive by default. For aspect-ratio preservation, use a CSS aspect-ratio container. Debounce resize events.

Accessibility

Ensure labels and legends remain readable at all sizes. If chart becomes too small, hide the chart and show the data table instead.

January February March April May

Axis Label Rotation dataviz-039

Rotate x-axis labels 45 or 90 degrees when they overlap at smaller widths. The fallback for long category labels in bar and line charts. Prefer horizontal labels when space permits — rotated text is harder to read.

Implementation

Recharts: XAxis angle={-45} textAnchor="end". Auto-detect overlap and rotate only when needed. Alternative: truncate labels with ellipsis and show full label in tooltip.

Accessibility

Rotated text must remain readable at the final angle. Minimum font size 11px even when rotated. For screen readers, the full label text is in the DOM regardless of rotation.

Desktop: daily Mobile: weekly Fewer points, larger targets

Mobile Chart Simplification dataviz-040

On mobile, reduce chart complexity: fewer data points, simplified axes, larger touch targets, horizontal scroll for wide charts. Mobile users need trends, not precision — prioritize the story over the detail.

Implementation

Downsample data for mobile (show weekly instead of daily). Hide secondary axes. Increase tick spacing. Show only the top 5 bars. Use a horizontal scrollable container for dense charts with snap points.

Accessibility

Touch targets for interactive points: minimum 44x44px. Tooltip triggered by tap (not hover). Ensure swipe does not conflict with page scrolling.

Chart Skeleton Loading dataviz-041

Show a placeholder skeleton matching the chart shape while data loads. Prevents layout shift and communicates that content is coming. Better than a spinner because it preserves the spatial context.

Implementation

Render an SVG or div matching the chart dimensions with animated pulse backgrounds. shadcn: Skeleton component sized to match chart. Animate with CSS @keyframes. Transition to real chart with a fade.

Accessibility

aria-busy="true" on the chart container while loading. aria-label="Loading chart data". Remove aria-busy when data appears. Do not use aria-live for the loading state — only for the loaded state.

Desktop: grid Mobile: scroll

Stacked-to-Scrollable Layout dataviz-042

On desktop, show multiple charts side by side in a grid. On mobile, either stack vertically (for few charts) or use a horizontal scroll carousel (for many charts). Prevents tiny, unreadable charts on narrow screens.

Implementation

CSS Grid with auto-fill, minmax(320px, 1fr). Below 320px per chart, switch to a single column. For dashboard tabs, use swipeable tab panels on mobile. Add scroll snap for horizontal carousels.

Accessibility

Horizontal scroll containers need role="region" with aria-label. Include visual scroll indicators. Ensure all charts are reachable via keyboard (Tab / arrow keys).