Layout Tables Versus Data Tables: When to Use role=“presentation”

Permalink to "Layout Tables Versus Data Tables: When to Use role=“presentation”"

A layout table uses <table> markup to position content on screen; a data table uses it to express relationships between values and their headers. The distinction matters because browsers expose the two differently: a data table gets table navigation commands, row and column announcements, and a place in the screen reader’s table list, while a layout table should get none of that. When the browser guesses wrong — and it does guess — users either lose the structure they need or wade through structure that means nothing.

This page covers how browsers make that guess, how role="presentation" overrides it, and how to make a real data table unambiguous. It extends semantic HTML table construction.

Spec reference

Permalink to "Spec reference"

HTML-AAM does not define the layout-table heuristic; each browser engine implements its own. Chromium and Firefox both consider a table “layout” when it has no <th>, no <caption>, no <thead>, a single row or column, nested tables, or very few cells, and consider it “data” when it has header cells, a caption, borders on cells or many rows. The heuristic is a repair mechanism for the old web, and you should never rely on it for anything you author.

ARIA 1.2 defines role="presentation" and its synonym role="none" as removing the implicit semantics of an element. On a <table>, the presentational role propagates to the required owned elements — <tr>, <td>, <th>, <tbody> — so the whole structure flattens to its text. Content inside the cells stays fully accessible; only the table semantics go.

SC 1.3.1 Info and Relationships (Level A) is the criterion on both sides. A data table whose header relationships are lost fails it; a layout table that exposes meaningless rows and columns does not strictly fail, but it adds noise that the criterion’s intent is about avoiding.

Is this a data table? Decision tree starting with whether any cell's meaning depends on a header, leading to data table, presentation layout table or a CSS layout rewrite. Is this a data table?Does any cell need its row or column header to makesense?YesData tablecaption, th with scope, thead andtbodyNo, legacy markuprole="presentation"flatten it; strip th, caption andscopeNo, new codeCSS grid or flexboxa table element is the wrong tool
The question is always about relationships between cells — not about how the content looks.

When to use role=“presentation” — and when not to

Permalink to "When to use role=“presentation” — and when not to"

Use it for legacy layout tables you cannot rewrite yet: email templates rendered in a web view, CMS content from a decade ago, or a third-party widget’s markup. Adding the role is a one-attribute fix that removes table noise immediately.

Do not use it on anything that is actually tabular, however simple it looks. A two-column key–value list (“Status: Paid”, “Due: 4 March”) is a data table if the left column labels the right; if you do not want table semantics for it, use a description list (<dl>) rather than a presentational table.

The misapplication to name is adding role="presentation" to a data table to silence an axe-core or HTML validator warning about missing headers. That swaps a fixable warning for a real loss of structure. Fix the headers instead.

Also do not reach for it when a table is visually restyled for mobile. Changing display on table elements already strips semantics in some browsers — that is a bug to fix, as shown in stacked card layouts that keep table semantics, not a reason to remove them deliberately.

Signals the browser reads Comparison of markup signals that push the browser toward classifying a table as data versus layout. Signals the browser reads✓ Signals "data table"A caption elementth cells with scopethead, tbody or tfootSeveral rows and columns of valuesrole="table" or role="grid" set explicitly✗ Signals "layout table"No th cells anywhereA single row or a single columnA nested table inside a cellrole="presentation" or role="none"Cells holding whole content blocks
A data table you author should carry every signal on the left, so no heuristic ever has to guess.

Annotated code example

Permalink to "Annotated code example"
<!-- LEGACY LAYOUT TABLE: flattened so no table semantics are exposed -->
<table role="presentation">          <!-- ARIA: propagates to tr/td -->
  <tr>
    <td><img src="logo.png" alt="Northwind Traders"></td>
    <!-- content inside the cell stays fully accessible -->
    <td><h1>Monthly statement</h1></td>
  </tr>
</table>

<!-- DATA TABLE: every signal present, nothing left to heuristics -->
<table>
  <caption>Statement lines, March 2026</caption>  <!-- SC 1.3.1 -->
  <thead>
    <tr>
      <th scope="col">Date</th>                    <!-- SC 1.3.1 -->
      <th scope="col">Description</th>
      <th scope="col">Amount (EUR)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>2026-03-04</td>
      <td>Subscription</td>
      <td>49.00</td>
    </tr>
  </tbody>
</table>

A presentational table must not contain <th>, <caption> or scope. If it does, browsers resolve the conflict by ignoring the role — ARIA’s presentational-role conflict resolution says a focusable element or one with global ARIA attributes keeps its semantics — and you end up with a half-flattened structure. Strip them.

Keyboard & AT behaviour

Permalink to "Keyboard & AT behaviour"
Event Data table Layout table with role=“presentation”
T in browse mode (NVDA/JAWS) Lands on the table, reads name and size Skipped — not a table
Ctrl+Alt+Arrow Moves by cell, reads headers Not available
Table list Listed under its caption Not listed
Linear reading (Down Arrow) Cell by cell with row/column context Plain content in source order
VoiceOver rotor, Tables Listed Absent
How the browser decides Flow from authored markup through the browser's layout-table heuristic to the role exposed in the accessibility tree and what the screen reader offers. How the browser decidesAuthoredmarkuptable element, withor without headersExplicit role?presentation, tableor grid winsoutrightHeuristicth, caption, size,borders, nestingTree roletable or layouttable (generic)AT behaviourtable commands, orplain reading
An explicit role or strong data-table markup short-circuits the heuristic — that is the goal.

Integration context

Permalink to "Integration context"

Layout tables mostly turn up in content rather than components: CMS rich text, imported documentation, and HTML emails displayed inside a web app. An audit rule in your pipeline can flag tables with no <th> for review; the configuration for that is in configuring axe-core rules and handling false positives.

For interactive data, the next decision after “this is a data table” is whether it should be a static table or an interactive grid, covered in choosing between grid and table roles.

Gotchas

Permalink to "Gotchas"

A single-row data table. A one-row summary table (“Total: 4,210 · Paid: 3,900 · Due: 310”) is often classified as layout by the heuristic. Add a caption and <th scope="col"> cells, or express it as a <dl>.

Focusable content inside presentational cells. Links and buttons inside a role="presentation" table work normally. But if you add tabindex or aria-* to the <td> itself, that cell keeps its semantics and the flattening becomes partial.

Nested data table inside a layout table. The presentation role does not propagate into a nested <table>. A real data table inside a legacy layout wrapper stays a data table — which is what you want, but only if it has its own headers.

Testing checklist

Permalink to "Testing checklist"

FAQ

Permalink to "FAQ"
How can I see whether the browser treats my table as layout?

Open the accessibility tree in Chrome or Firefox DevTools and inspect the table element. A data table shows the table role with rows and cells beneath it; a layout table shows a generic or layout-table role, and its rows and cells are not exposed as table structure.

What is the difference between role="presentation" and role="none"?

None in behaviour. ARIA 1.1 introduced role=“none” as a clearer synonym because “presentation” was often misread as “this is a presentation”. Both remove the element’s implicit semantics; use whichever your codebase uses consistently.

Will role="presentation" hide the table's content from screen readers?

No. It removes the table semantics — rows, columns, headers — but the text, images, links and headings inside the cells remain fully accessible and are read in source order. To hide content entirely you would need aria-hidden, which is a different thing.

Is a key–value list a data table?

If the left column labels the right, the relationship is real and must be programmatic. A two-column table with th scope=“row” for the keys works; a description list with dt and dd is usually simpler and avoids table navigation for what is really a list.

Permalink to "Related"

← Back to Semantic HTML Table Construction