Why this matters
Reusable chart components save weeks of effort across dashboards. As a Data Visualization Engineer, you will standardize look-and-feel, ensure accessibility, speed up delivery, and reduce bugs. Real tasks include: building a BarChart used by 20+ reports, enabling small multiples without extra code, exposing a consistent theming API, and shipping accessible charts with keyboard and screen reader support.
Who this is for
- Data Visualization Engineers translating analytics into consistent, brand-aligned charts.
- BI developers maintaining many dashboards who need a single source of truth for charts.
- Frontend engineers integrating charts into design systems.
Prerequisites
- Comfort with a UI framework or rendering layer (SVG/Canvas concepts).
- Basic knowledge of scales (linear, band, time) and axes.
- Understanding of theming tokens (colors, typography, spacing).
- Basic accessibility concepts (ARIA, roles, labels, keyboard focus).
Concept explained simply
A reusable chart component is a small, configurable machine. You give it data and configuration; it returns a consistent visual with the right behavior and accessibility built in. The API should be predictable, minimal, and theme-aware.
Mental model
- Adapter layer: normalize raw data into a consistent shape.
- Chart core: map data to visual primitives (scales, axes, marks).
- Styling & theming: apply tokens and variants to visuals.
- Interaction hooks: events like onHover, onSelect; tooltips and focus states.
- Accessibility: roles, labels, descriptions, tab order.
See a minimal but powerful chart API
{
data: Array,
x: accessor | fieldName,
y: accessor | fieldName,
width, height, margin,
xScale: { type: 'band'|'linear'|'time', domain?, nice? },
yScale: { type: 'linear', domain?, nice? },
colors: { scheme: 'brand'|'category10'|Array, by?: 'series'|'category' },
theme: 'light'|'dark'|{ tokens... },
a11y: { ariaLabel, ariaDescription, announceOnFocus?: true },
interactions: { onHover?, onClick?, focusable?: true },
layout: { direction?: 'vertical'|'horizontal' }
}
Design criteria for reusability
- Stable API: use clear, typed props with sensible defaults.
- Separation of concerns: data adaptation separate from rendering.
- Theming-first: accept design tokens; avoid hard-coded colors.
- Composable: optional layers (gridlines, legends, annotations) toggled via flags/slots.
- Accessible by default: ARIA roles, keyboard focus, color-contrast, reduced motion.
- Performance-aware: avoid re-computing scales; memoize; support Canvas for large series if needed.
- Deterministic: no hidden I/O or global state; pure rendering from props.
Worked examples
Example 1 — Reusable BarChart
Goal: a vertical BarChart usable for categorical comparisons and small multiples.
- Inputs: data, x (category), y (value), width, height, margin, colors, a11y.
- Compute xScale (band), yScale (linear), and barWidth (bandwidth).
- Render axes, gridlines (optional), bars with consistent radius and gaps.
- Attach interactions (hover, click) and focus ring for keyboard users.
- Apply theme tokens for fills, strokes, text, and grid.
Why this design works
- Band scale + margins = predictable spacing across dashboards.
- Deterministic rendering makes snapshot tests stable.
- Theming drives color and typography without per-chart overrides.
Common variations
- Horizontal bars: flip scales and axes.
- Stacked bars: accept series accessor and stack function; add legend slot.
- Small multiples: map an array of datasets to multiple BarChart instances with shared theme.
Example 2 — Time-series LineChart
Goal: a trend line with optional markers, baseline, and anomalies.
- Inputs: data, x (date), y (value), width, height, margin, colors, curve, showPoints.
- Time scale for x, linear scale for y; nice domains; optional yZero baseline.
- Render path for line; optional circles for points; accessible title and description.
- Hover interaction: highlight nearest point, show formatted tooltip content via callback.
Variation: Sparkline mode
Hide axes, grid, points; compact padding; rely on aria-label to describe trend.
Example 3 — KPI Sparkline micro-component
Goal: a tiny, embeddable sparkline for dense KPI tables.
- Inputs: data, x, y, width (80–120), height (20–32), strokeWidth, positiveColor, negativeColor.
- Compute min/max; color by last delta sign; no axes; minimal margin.
- Focusable wrapper with aria-label like "Revenue trend last 12 weeks: upward".
Why it is reusable
Same API works for any KPI series; theme tokens drive colors; fits any row height.
Reusable patterns and conventions
- Naming: x, y for primary accessors; series for grouped/stacked data; layout for orientation.
- Defaults: provide opinionated defaults (margins, grid) with opt-out flags.
- Slots: legend, annotations, tooltip content as render slots or callbacks.
- Configuration layering: component defaults < theme defaults < per-instance overrides.
- Deterministic ids: generate predictable ids for clipPaths/gradients (e.g., from stable keys).
Accessibility and i18n essentials
- Role: set appropriate roles and titles; provide aria-label and aria-description.
- Keyboard: focusable containers; arrow keys to move focus between marks if interactive.
- Color contrast: ensure minimum contrast for lines/text; do not encode meaning by color alone.
- Reduced motion: respect prefers-reduced-motion for transitions.
- Number/date formatting: accept formatters to localize labels and tooltips.
Performance tips
- Memoize scales and derived arrays; avoid recalculating on unrelated prop changes.
- Batch renders; prefer Canvas for tens of thousands of marks.
- Defer heavy tooltips; compute on demand (nearest point only).
- Avoid layout thrashing; compute sizes once from width/height props or a parent container.
Testing your components
- Unit: scale domains, accessors, formatting functions.
- Visual: snapshot SVG output with stable ids and seed; compare for regressions.
- A11y: verify roles, labels, focus order, and tab stops.
- Contracts: test that props validation rejects invalid combinations early.
Exercises
-
Exercise 1: Design a reusable BarChart API (ex1)
Create an API spec and two usage examples: one vertical, one horizontal. Include a11y and theming.
- List required and optional props with defaults.
- Describe how data is adapted (accessors).
- Show how theming tokens are applied.
- Provide event callbacks (onHover/onClick) signature.
Need a nudge?
Think in layers: adapter, core, theme, interactions. Keep props minimal; allow overrides via callbacks.
After you try it, open the solution in the exercise panel below the lesson.
Exercise checklist
- API includes data, accessors, dimensions, scales, theme, a11y, interactions.
- Defaults cover margins, grid, and color scheme.
- Examples show both vertical and horizontal bars.
- A11y labels describe the chart purpose and content.
Common mistakes and how to self-check
- Hard-coded colors or fonts: replace with theme tokens; verify theme swap changes the chart.
- Mixing data fetch with rendering: keep components pure; pass data via props.
- Unstable ids causing flaky tests: generate deterministic ids from stable keys.
- Overloaded props (too many flags): prefer composable slots and sensible defaults.
- Ignoring keyboard interaction: tab through the chart; ensure focus rings and ARIA labels exist.
Practical projects
- Build a mini chart kit: BarChart, LineChart, Sparkline, and Legend with a shared theme.
- Create a small-multiples dashboard using your BarChart with 6–12 panels sharing scales.
- Add annotations and thresholds to LineChart with a pluggable annotations slot.
Learning path
- Start with BarChart (categorical) and LineChart (time-series) foundations.
- Add theming and accessibility defaults to both.
- Introduce composition: legends, tooltips, annotations as optional slots.
- Scale up performance: memoization and Canvas fallback for large datasets.
Next steps
- Refactor your existing charts to use the new reusable components.
- Publish a design tokens map for chart colors, text, and gridlines.
- Add tests: scale domain, snapshot, and a11y.
Mini challenge
Extend your BarChart to support stacked bars using a series accessor. Acceptance criteria: a legend slot, correct stacking order, accessible labels for each segment, and keyboard navigation between segments.
Hints
- Normalize data to an array of series per category before computing stacks.
- Share xScale; compute yScale on summed values.
- Use focus management: arrow keys move within a stack; tab moves across categories.
Quick test
Take the quick test to check your understanding. Available to everyone. Note: only logged-in users will have their progress saved.