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> or role="search", <footer> (contentinfo). Screen readers list landmarks and jump between them (NVDA D, JAWS R, VoiceOver rotor).
  • Headings (<h1>–<h6>) are the most used navigation structure; users jump by H or 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).

A dashboard's navigable structure Layers of a dashboard's structure: banner, navigation, a search landmark for global filters, the main landmark with an h1, and widgets each with an h2. A dashboard's navigable structurebanner + navigationsite header and app navigation — the usual landmarkssearch landmarkglobal filters: date range, region, segment — named "Dashboard filters"main + h1"Sales overview, March 2026" — one per pagewidgets, each with h2"Revenue", "Orders by channel", "Top accounts" — in visual reading ordercomplementary (optional)activity feed or notes panel, named
Landmarks for the few major areas; headings for every widget — that is enough to navigate any dashboard.

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
Card per region versus heading per card Comparison of making every dashboard card a named region against giving every card a heading and reserving regions for major areas. Card per region versus heading per card✗ Every card a regionLandmark list of 20+ entriesDuplicates what headings would doRegion names often repeat the title twiceUsers stop using landmarks✓ Heading per cardHeadings list is the dashboard outlineLandmarks kept for 4–6 major areasJump by heading level between widgetsMatches how users navigate documents
Headings scale to any number of widgets; landmark lists do not.

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.

Visual layout and heading order Mock of a three-column dashboard grid with each widget numbered in the order its heading appears in the DOM, matching left-to-right, top-to-bottom reading. Visual layout and heading orderColumn 1Column 2Column 3Revenue (h2)1Orders (h2)Margin (h2)Orders by channel …2Orders by chan…Top accounts (…3Activity (aside)ActivityActivity1KPI cards first: h2 each, left to right2A wide chart spans two columns but is onewidget, one heading3Top accounts follows the chart in the DOM,matching the visual order
DOM order should follow the visual reading order, so the headings list reads like the screen.

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.

Permalink to "Related"

← Back to Data Dashboards