Landmarks and Headings for Data Dashboards
Permalink to "Landmarks and Headings for Data Dashboards"A dashboard is a page of many small, independent pieces: KPI cards, charts, tables, a filter bar, maybe an activity feed. Sighted users scan it spatially and jump to what they need. Screen reader users navigate by structure — headings and landmarks — and a dashboard built from <div> cards with styled text titles gives them nothing to jump between. They are left reading every number on the page in DOM order.
This page gives dashboards the structure that makes them navigable: landmarks for the major areas, a heading per widget, and restraint about naming every card as a region. It belongs to data dashboards.
Spec reference
Permalink to "Spec reference"- Landmarks come from HTML elements and roles:
<header>(banner),<nav>(navigation),<main>(main),<aside>(complementary),<form>/<section>with an accessible name (form/region),<search>orrole="search",<footer>(contentinfo). Screen readers list landmarks and jump between them (NVDAD, JAWSR, VoiceOver rotor). - Headings (
<h1>–<h6>) are the most used navigation structure; users jump byHor by level (1–6). - A
<section>is only a region landmark when it has an accessible name. An unnamed<section>is a generic container.
Criteria: SC 1.3.1 Info and Relationships (structure is programmatic), SC 2.4.1 Bypass Blocks (landmarks and headings let users skip repeated content), SC 2.4.6 Headings and Labels (headings describe their content), SC 2.4.10 Section Headings (AAA, but good practice for dashboards).
When to use regions — and when headings are enough
Permalink to "When to use regions — and when headings are enough"Use named regions for a handful of major areas that users want to jump to directly: the filter area, perhaps an alerts panel, perhaps a secondary sidebar. Screen reader landmark lists work best with five to eight entries.
Use headings — not regions — for individual widgets. A dashboard with twenty cards, each a named region, produces a twenty-entry landmark list that is no faster than reading the page. Headings give the same jump-to capability with a structure users expect.
The misapplication to name is widget titles styled as headings but marked up as <div class="card-title">. Visually they are headings; to a screen reader, they are plain text among numbers.
Annotated code example
Permalink to "Annotated code example"<header>…app header…</header>
<nav aria-label="Primary">…</nav>
<!-- SC 2.4.1: global filters findable as a landmark -->
<search aria-label="Dashboard filters">
<form>… date range, region, segment …</form>
</search>
<main>
<h1>Sales overview, March 2026</h1> <!-- one h1 -->
<!-- Widgets: headings in visual reading order; no region per card -->
<article class="widget kpi">
<h2>Revenue</h2> <!-- SC 1.3.1 + 2.4.6 -->
<p class="kpi-value">€1.28M <span class="delta">up 4% on February</span></p>
</article>
<article class="widget chart">
<h2 id="w-orders">Orders by channel</h2>
<figure aria-labelledby="w-orders">…chart + summary…</figure>
</article>
<article class="widget table">
<h2 id="w-top">Top accounts</h2>
<table aria-labelledby="w-top">…</table>
</article>
</main>
<!-- A secondary area worth a landmark -->
<aside aria-label="Activity">
<h2>Recent activity</h2>
<ol role="log" aria-label="Recent activity" aria-live="off">…</ol>
</aside>
<article> fits dashboard widgets well — each is a self-contained unit — and does not create a landmark. The <search> element is new in HTML and maps to the search landmark in current browsers; <div role="search"> is the fallback for older ones.
Keyboard & AT behaviour
Permalink to "Keyboard & AT behaviour"| Command | Expected result |
|---|---|
NVDA D / JAWS R / VO rotor Landmarks |
banner, Primary navigation, Dashboard filters, main, Activity |
H repeatedly |
Sales overview, Revenue, Orders by channel, Top accounts, Recent activity |
2 (next h2) |
Jumps widget to widget |
| NVDA elements list, Headings | Outline of the dashboard in reading order |
Tab |
Interactive elements only — filters, chart, table controls |
Integration context
Permalink to "Integration context"Headings make widgets findable; moving between them with the keyboard — and into and out of their interactive content — is covered in keyboard navigation between dashboard widgets. Widget headings also give each widget’s chart or table its name through aria-labelledby, as in labelling grids and tables with aria-labelledby.
When the dashboard refreshes, the headings are how users re-orient after hearing a summary; see announcing dashboard refreshes.
Gotchas
Permalink to "Gotchas"CSS grid reordering. grid-template-areas and order can place widgets visually in a different order from the DOM, so headings are read in an order that does not match the screen (SC 1.3.2). Keep DOM order equal to visual order.
User-customisable layouts. When users drag widgets around, re-order the DOM to match, not just the grid positions.
Heading levels in embedded widgets. A widget component that hard-codes <h3> breaks the outline when placed at a different depth. Pass the heading level as a prop.
Design system notes
Permalink to "Design system notes"A dashboard widget component should require a title and render it as a heading at a configurable level (default h2), use <article> as its wrapper, and expose the heading id so charts and tables inside can use aria-labelledby. Provide a separate filter-bar component that renders a named search landmark.
Testing checklist
Permalink to "Testing checklist"FAQ
Permalink to "FAQ"Should every dashboard card be a landmark region?
No. Too many landmarks make the list useless. Give every card a heading, and reserve named regions for a few major areas such as the filter bar and a sidebar.
What heading structure should a dashboard use?
One h1 for the dashboard, then one heading per widget, usually h2, in the same order as the widgets appear visually. Group widgets under h2 section headings with h3 widget headings if the dashboard has distinct sections.
Where should dashboard filters go in the markup?
Before the widgets they affect, inside a search landmark (or a region) named “Dashboard filters”, so users can jump to them by landmark.
Should dashboard widgets use article or section elements?
article suits self-contained widgets that make sense on their own, such as a KPI card or a chart, and it does not create a landmark. A section with an accessible name becomes a region landmark, so reserve named sections for the few major areas users need to jump to.
What should the dashboard's h1 say?
What the dashboard shows and for which scope — “Sales overview, March 2026” or “Support queue, Team North” — so users hear the context as soon as they land. Update it when the scope changes through filters, if the scope is part of the title.
Does CSS grid layout affect screen reader order?
Yes, if you reorder items visually with grid placement or order. Screen readers follow DOM order, so keep the DOM in the same order users see.
Related
Permalink to "Related"- Keyboard navigation between widgets — moving between cards
- Accessible KPI cards — the smallest widgets
- Labelling with aria-labelledby — naming regions from headings