1.3.1 Info and Relationships

WCAG 2.2 · 1.3.1 A Perceivable

What it requires

Information, structure, and relationships that are conveyed through presentation must also be programmatically determinable or available in text. In other words, anything a sighted user infers from visual layout — that a row of text is a heading, that fields belong to a group, that bold text is a list, that a cell is a table header for its column — must be expressed in the markup so assistive technology can convey the same meaning. Visual styling alone is never enough; the relationship has to exist in the code (native HTML elements or ARIA) or be stated in the visible text.

It mainly affects people who do not perceive the visual presentation:

  • Screen reader users (blind or low-vision) rely on programmatic structure to understand headings, lists, tables, and form labels, and to navigate by them.
  • People who customize styling (custom stylesheets, high-contrast or reading modes) lose visual-only cues such as colour, position, or font weight.
  • Some people with cognitive disabilities benefit from consistent, machine-readable structure that tools can reflow or simplify.

How to detect it

Concrete checks for Info and Relationships
Check What to look for Automated?
Headings Visual headings use real h1h6, not styled div/p; order is logical. Partly — tools flag fake headings poorly.
Lists Bulleted/numbered content uses ul/ol/li, not dashes or br. Partly.
Tables Data tables have th with correct scope; layout isn't faked with tables. Partly — axe catches missing headers.
Forms Each control has a programmatic label; groups use fieldset/legend. Yes — axe reliably flags missing labels.
Screen reader / keyboard Navigate by headings, lists, and tables; confirm announced structure matches the visual. Manual only.

Automated tools (e.g. axe, WAVE) catch some failures — missing labels, empty headings, tables without headers — but cannot tell whether a visual heading was marked up as a heading, so manual and screen-reader review are required.

How to fix it

  1. Use the correct native HTML element for each role: headings, lists, tables, and grouped form fields.
  2. Give data tables th cells with an explicit scope, and group related form controls with fieldset and legend.
  3. Associate every form control with a label (via for/id or wrapping).
  4. Where native semantics don't fit, add ARIA roles and properties to expose the relationship — but prefer native elements first.
  5. Never rely on colour, position, or weight alone to convey meaning; put the relationship in markup or in visible text.
<fieldset>
  <legend>Shipping address</legend>
  <label for="city">City</label>
  <input id="city" name="city" type="text">
</fieldset>

<table>
  <tr><th scope="col">Plan</th><th scope="col">Price</th></tr>
  <tr><th scope="row">Basic</th><td>$9</td></tr>
</table>

Copy-paste tests

Automated coverage

These axe-core rules flag failures of this criterion: aria-hidden-body, aria-required-children, aria-required-parent, definition-list, dlitem, list, listitem, p-as-heading, table-fake-caption, td-has-header, td-headers-attr, th-has-data-cells. Run them via the axe DevTools browser extension or axe-core in CI. Automated tools only catch some failures — the rest need human review.

Run this in the browser console

find-structure.js
// Read-only: surface elements whose structure may not match their meaning.
const suspects = [];
document.querySelectorAll('table:not([role]):not(:has(th)), ' +
  'b, i, font, [style*="font-weight"], [style*="font-size"], ' +
  'ul ul, ol ol, [role="list"]:not(ul):not(ol)').forEach(el => suspects.push(el));
suspects.forEach(el => el.style.outline = '2px solid magenta');
console.table(suspects.map(el => ({ tag: el.tagName, text: (el.textContent || '').trim().slice(0, 40) })));
console.log('Review each: is its visual structure conveyed in the markup?', suspects);

What to check manually: confirm that visually grouped content (a "table" of aligned text, bold pseudo-headings, label/value pairs) is encoded with real semantic markup, and that reading order in the DOM matches the meaningful order a sighted user perceives.