Linked Chart and Table Highlighting

Permalink to "Linked Chart and Table Highlighting"

Dashboards often pair a chart with a table: hover a bar and its row lights up; click a row and the matching point is emphasised. Done well, linked highlighting helps everyone — sighted users connect the picture to the numbers, and screen reader users can use the table as their main view while the chart follows along for sighted colleagues. Done badly, it is hover-only, one-directional and colour-coded, and it actually makes the page noisier for assistive technology.

This guide belongs to interactive chart controls.

Spec reference

Permalink to "Spec reference"
  • SC 2.1.1 Keyboard (A) — linking triggered by hover must also be triggered by focus.
  • SC 1.4.1 Use of Color (A) — the highlighted row or point needs a non-colour indicator (outline, weight, marker).
  • SC 1.3.1 Info and Relationships (A) — the linked state should be programmatic (aria-selected or aria-current="true" on the row).
  • SC 3.2.1 On Focus (A) — focusing a row may highlight the chart (a change of content), but must not move focus into the chart.
  • SC 4.1.3 Status Messages (AA) — only announce linkage when it adds information the focused element does not already give.
Two-way linking driven by keyboard Sequence among table, shared state and chart: focusing a row sets the shared selection; the chart highlights the matching point; arrowing in the chart sets the selection; the table marks the row as current. Two-way linking driven by keyboardTableShared stateChartfocus row "Q3"highlight Q3 barRight arrow to Q4 in chartrow Q4 aria-current="true"
One shared state, two views, no focus jumps.

When to use — and when not to

Permalink to "When to use — and when not to"

Link chart and table whenever both are visible together and represent the same data. Make the table the primary view for keyboard and screen reader users, with linkage as a convenience.

Do not move focus from table to chart (or back) automatically. Do not announce “Q3 highlighted in chart” on every row focus — the row already says “Q3”. The misapplication: hover-only linking, so keyboard users never see the connection, combined with a colour-only highlight.

Hover-only linking versus shared-state linking Comparison: hover-only linking ignores keyboard focus and uses colour; shared-state linking responds to focus and selection in both views with programmatic and non-colour indicators. Hover-only linking versus shared-state linking✗ Hover-only, one wayKeyboard focus ignoredColour-only highlightRow state not programmaticFocus jumps on click✓ Shared state, two wayFocus in either view updates the otherOutline and marker plus colouraria-current="true" on the linked rowFocus stays; commands move it

Annotated code example

Permalink to "Annotated code example"
// One source of truth for the linked item
const selection = new EventTarget(); let current = null;
function select(id, source) { current = id; selection.dispatchEvent(new CustomEvent('change', { detail: { id, source } })); }

// Table → state (focus and hover both)
table.addEventListener('focusin', (e) => { const r = e.target.closest('tr[data-id]'); if (r) select(r.dataset.id, 'table'); });
table.addEventListener('pointerover', (e) => { const r = e.target.closest('tr[data-id]'); if (r) select(r.dataset.id, 'table'); });

// Chart → state (keyboard navigation and hover)
chart.on('pointfocus', (id) => select(id, 'chart'));

// State → both views; never move focus (SC 3.2.1)
selection.addEventListener('change', ({ detail: { id, source } }) => {
  chart.highlight(id);                                                     // outline + marker (SC 1.4.1)
  table.querySelectorAll('tr[aria-current]').forEach(r => r.removeAttribute('aria-current'));
  table.querySelector(`tr[data-id="${id}"]`)?.setAttribute('aria-current', 'true');   // SC 1.3.1
});

// Explicit cross-view commands
chart.on('keydown', (e) => { if (e.key === 'Enter') table.querySelector(`tr[data-id="${current}"] th`)?.focus(); }); // "Go to row"
tr[aria-current="true"] { outline: 2px solid var(--brand-strong); font-weight: 600; }   /* not colour alone */
.point.highlight { r: 6; stroke: var(--ink); stroke-width: 2; }

Keyboard & AT behaviour

Permalink to "Keyboard & AT behaviour"
Event Expected result Announcement
Arrow to row Q3 in table Chart highlights Q3 Row as usual; no extra message
Arrow to Q4 in chart Table row Q4 marked current Point announcement (from the chart)
Enter in chart Focus moves to Q4 row Row read
“Show in chart” on a row Focus moves to chart at Q4 Point announcement
Mouse hover Same linkage —
What to announce in linked views Matrix of events — focus a row, focus a point, select a row that filters other charts, hover — against whether to announce and what. What to announce in linked viewsAnnounce?MessageFocus a rowNorow content sufficesFocus a pointNopoint announcement sufficesSelect a row that filtersother viewsYes"Other charts filtered to Q3"HoverNovisual only
Announce only effects the user cannot hear from the focused element.

Integration context

Permalink to "Integration context"

The chart side uses keyboard navigation from canvas & SVG chart keyboard interaction; the table side follows sortable & filterable data grids. Range selections that filter linked views are covered in brush selection alternatives for range filtering. Dashboard-wide filters are discussed in dashboard filters that apply across widgets.

Gotchas

Permalink to "Gotchas"

Highlight versus filter. Highlighting emphasises; filtering removes. If clicking a row filters other charts, that is a filter and needs announcement and a clear way to undo.

Scroll jumps. Highlighting a row far down a long table should not scroll the table while the user is in the chart; show an indicator (“Row 214”) instead.

Multiple tables. If several tables link to one chart, keep one selection state and mark the row in each.

Common mistakes

Permalink to "Common mistakes"
  • Linking on hover only.
  • Highlighting with colour only.
  • Moving focus between views automatically.
  • Announcing linkage that adds nothing.

Framework notes

Permalink to "Framework notes"

Vega-Lite selections (point, interval) can drive both chart encodings and table views through shared signals. ECharts connect links charts; for tables, listen to highlight and downplay actions. In React, keep the selection in context or a store; in Angular, a service with a BehaviorSubject; avoid component-local state that only one view can see.

// ECharts: table row focus highlights a bar
row.addEventListener('focus', () => chart.dispatchAction({ type: 'highlight', seriesIndex: 0, dataIndex: i }));

Worked example

Permalink to "Worked example"

A sales dashboard linked a bar chart of regions to a table, but only on mouse hover and only in one direction. A screen reader user working in the table could not show colleagues which bar they were discussing. The team moved to a shared selection: table focus highlights the bar with an outline and a marker, chart focus marks the row with aria-current and bold text, Enter in the chart jumps to the row, and “Show in chart” on each row jumps the other way. During screen-shared meetings, the chart now follows the screen reader user’s position in the table.

Testing checklist

Permalink to "Testing checklist"

Design system notes

Permalink to "Design system notes"

Provide a shared useLinkedSelection (or service) and require chart and table components to accept selectedId and emit onSelect for both focus and hover. Document highlight versus filter semantics.

FAQ

Permalink to "FAQ"
Should screen reader users hear that the chart highlighted something?

Usually not; it duplicates the row they are on. It helps sighted colleagues and keyboard users who can see both.

aria-selected or aria-current for the linked row?

aria-current=“true” suits “the item currently linked”; aria-selected suits grids with selection. Do not overload selection if the grid already uses it.

Can linking go chart → table → other charts?

Yes, through the shared state. Announce only when other views are filtered, not merely highlighted.

How should touch users trigger linking?

Tap on a row or point selects it; the other view highlights. Tap again to clear.

Should the chart scroll to show a highlighted point?

If the chart is zoomed and the point is off-screen, show a cue or pan with an announcement; do not pan silently.

What if the table is paginated?

Highlighting a point on another page should show “Row on page 3” with a link, rather than jumping pages.

Permalink to "Related"

← Back to Interactive Chart Controls