kyle.berry
Writing

Three places dashboards fail on accessibility

Notes from studying a11y in data-dense UIs: the patterns that are easy to miss when a table has thousands of rows.

3 min read
  • accessibility
  • dashboards
  • engineering

Dashboards are where accessibility gets hard. Forms have decades of established patterns. Navigation has landmarks. But a table with 5,000 rows, inline sparklines, and keyboard-editable cells? The spec is underspecified. You have to reason it out from first principles.

These are patterns I keep returning to when building or reviewing data-heavy UIs.

1. Color as the only signal

The classic mistake. A red cell means "overdue," a green cell means "paid," and a user with red-green color vision deficiency sees two identical shades. Fix it with a second signal: an icon, a text prefix, or a strikethrough. What I reach for is a short text label ("Overdue", "Paid") that carries the meaning, with color as reinforcement. Color enhances the label instead of being the only thing that says it.

2. Charts with no text alternative

SVG charts rendered by Highcharts, D3, or Recharts are invisible to screen readers by default. At minimum, add role="img" and an aria-label that describes the trend, not just the chart type. Better: provide a summary table as a visually-hidden sibling. "Revenue by month: Jan $12k, Feb $14k..." gives far more value than "bar chart."

3. Virtualized lists that skip the DOM

Virtualization is mandatory at scale. Rendering 10,000 rows naively destroys scroll performance. But virtual lists only mount a window of items, which means screen reader users who navigate by "jump to next table row" hit the end of the rendered window and stop, even when there are thousands more rows below.

A note on i18n and ARIA labels

Locale formatting and accessible labels are more entangled than they look. A number formatted as 1.234,56 in a German locale is 1,234.56 in a US locale. If you concatenate raw numbers into an aria-label, you'll produce nonsense in one of them. The fix: always pass display values through Intl.NumberFormat and Intl.DateTimeFormat before they reach the DOM or any aria string. Never concatenate raw number values.

The gap I keep noticing

Keyboard-shortcut discoverability. Power users who live in a dashboard build muscle memory for shortcuts, but most dashboards never surface those shortcuts anywhere in the UI. A simple ? modal listing the available shortcuts (like GitHub's) is cheap to build and helps anyone who relies on the keyboard.