# A11Y-7 — Structure is programmatically determinable — semantic headings, lists, tables, and form groups; headings and labels describe their content

L1 · hybrid · Accessibility

**Fails when:** styled divs standing in for headings, lists, or tables · headings or labels that do not describe their content

## Requirement

Express the page's structure in markup, not just visually: real heading elements in
a logical hierarchy, lists as `ul`/`ol`, tabular data as tables, related form fields
grouped. Headings and labels describe the content they introduce; link text makes
sense read on its own.

## Rationale

The accessibility checklist Essential tier ("Presentation of info and relationships" +
"Headings and labels" + "Link text and purpose"). A person using a screen reader
navigates by headings and landmarks — visual-only structure is invisible to them.
This is also what makes pages legible to agents and checks: semantic markup is
machine-readable structure.

## Passes when

- One `h1` per view; heading levels nest without skipping; sections that look like
  sections are sectioned.
- A roster rendered as a list IS a list (`ol`/`ul`); data grids are tables with
  header cells.
- Headings name their content ("Attendance", "No notes yet"), not generic
  ("Overview", "Section 2").
- Link text describes the destination ("Make a correction"), never "click here".

## Fails when

- Styled `div`/`span` standing in for headings, lists, or buttons.
- Heading levels chosen for font size rather than hierarchy.
- A label that only makes sense with visual context ("More", "Here", bare icons).

## How to verify

**Static half:** `checks/structure-scan.py` (the `structure` check) flags a `<table>` or a
`role="table"` element whose subtree holds no `<th>` and no `role="columnheader"`. That
one table rule is the whole static half. It runs the same walk for CMP-6 and reports the
finding under both ids.

**Rendered half:** the rendered runner's axe rules `heading-order`, `list` and
`listitem` decide heading order and list semantics. No static heading walk ships: a
source scan cannot see a page assembled from a layout, MDX and components, so it would
flag good work.

**Judgment half:** the evaluator reads headings, labels and links out of visual context
and judges whether they still communicate, and decides whether styled divs should have
been a heading, a list or a table. Form grouping (`fieldset` / `legend`) stays manual: it
needs to know which fields are related.
