What 2.4.6 requires
Headings and labels describe topic or purpose.
People who use screen readers often move through a page by its headings, and everyone scans them. A heading that describes its section lets people find what they came for; a label that describes its field lets them fill it in.
Short is fine. Understanding 2.4.6 says a word, or even a single character, may be enough when it gives the right cue, such as a letter over one part of a glossary.
2.4.6 does not require headings or labels; it requires the ones you have to describe their topic or purpose. Marking them up is 1.3.1, providing labels is 3.3.2, and exposing a field’s name is 4.1.2. A field can have a perfectly exposed name and still fail 2.4.6, because the name says nothing.
Common failures
Under each example: what axe-core and Rampa reported on the markup before the fix, in a run with Gemma 4 12B on 8 October 2026.
A heading left from the template
“Title goes here” would fit any section of any page. Someone who lists the headings learns nothing about the opening hours under it.
Before, fails 2.4.6
<h2>Title goes here</h2>
<p>Monday to Friday, 7 am to 6 pm.
Saturday, 8 am to 1 pm.</p>After, passes
<h2>Opening hours</h2>- axe-core
Passes: no axe-core rule reads what a heading says.
- Rampa
✗ html > body > main > h2:nth-of-type(1) The heading "Title goes here" says nothing about the content under it. Evidence: "Title goes here" Patch: - <h2>Title goes here</h2> + <h2>Opening Hours</h2> confidence high · 1/1 runs · evidence verified · id 9d2d83dfbfbe
A heading that names another subject
The section is about returns and the heading says shipping. Someone jumping from heading to heading skips the part they need.
Before, fails 2.4.6
<h2>Shipping</h2>
<p>You can return unopened bags within
30 days for a full refund.</p>After, passes
<h2>Returns</h2>- axe-core
Passes: no axe-core rule reads what a heading says.
- Rampa
Rampa passed this heading in the recorded run: a miss. It also passed the same example in Portuguese.
Two fields with the same label
Both fields say “Name”, and nothing on the page tells the buyer from the recipient. Rampa puts that in the context as a fact, because whether the label describes the field depends on it.
Before, fails 2.4.6
<label for="from-name">Name</label>
<input id="from-name" autocomplete="name">
<label for="to-name">Name</label>
<input id="to-name">After, passes
<label for="from-name">Your name</label>
<input id="from-name" autocomplete="name">
<label for="to-name">Recipient’s name</label>
<input id="to-name">- axe-core
Passes:
labelfinds a label for each field.- Rampa
✗ #from-name The label "Name" does not say what to enter. Evidence: "Name" Patch: - <label for="from-name">Name</label> + <label for="from-name">Recipient Name</label> confidence high · 1/1 runs · evidence verified · id 49b6d05e23c8 ✗ #to-name The label "Name" does not say what to enter. Evidence: "Name" Patch: - <label for="to-name">Name</label> + <label for="to-name">Recipient Name</label> confidence high · 1/1 runs · evidence verified · id 1ac85dde1ec5Both findings are right, but the first suggestion is wrong: that field is the buyer’s. A patch is a proposal for a person to review.
What axe-core checks
axe-core 4.14.0 has no rule mapped to 2.4.6. Two rules sit next to it: label, mapped to 4.1.2, fails a form field with no label at all, and empty-heading, a best practice, fails a heading with no text. Rampa runs only rules tagged with WCAG A and AA, so label is part of a run and empty-heading is not; a field that label failed never goes to the model.
| Rule | What it checks | Mapped to | In a Rampa run |
|---|---|---|---|
label, rule page at Deque University | Form elements must have labels | 4.1.2 | runs |
empty-heading, rule page at Deque University | Headings should not be empty | best practice | not run: best practice |
Neither reads the text. “Title goes here”, a heading about the wrong subject and two fields both labeled “Name” pass every rule.
Each rule links to its page at Deque University, which makes axe-core.
What Rampa judges, and how
What goes to the model
Every visible heading that has text and something under it, and every visible form field with a name: text boxes, search boxes, combo boxes, list boxes, spin buttons, sliders, checkboxes and radio buttons.
What the model sees
- For a heading: its level and the content it introduces, up to the next heading of the same or a higher level or the end of its section element, about 700 characters. Fields in that content are described as fields, such as a textbox field labeled “Email”.
- For a heading, also: the headings of the sections it sits in, and the other headings at its level in the same section.
- For a label: the field’s role and type, its
name,id,autocompleteandplaceholder, the visible heading above it and the group it sits in, such as a fieldset’s legend. - When several fields share a label: a sentence saying whether a visible heading or group tells them apart.
- The page language, for the suggestion.
What it must answer
First, what the text names, in a few words, so the model reads it before judging it; then a verdict, the text copied as evidence, the problem (generic, a mismatch, or placeholder text), a suggested text under 80 characters, and a confidence.
What drops a claim
- The evidence is not the heading’s or label’s current text.
- A pass names a problem, or a fail names none.
- A fail has no suggested text, one over 160 characters, or one equal to the current text.
The patch
The suggested text replaces the heading’s text, the label element’s text, or the field’s aria-label.
For every criterion
- Page content reaches the model marked as data, and the prompt tells it to ignore any instruction inside.
- Answers are cached by a hash of the prompt, the image, the model and its settings, so the same input never calls a model twice.
--runs 3asks three times and keeps the majority; when runs disagree, confidence drops. Findings below--min-confidence(medium by default) are hidden, and--verboselists them.- Claims dropped by verification are counted in every report, never shown as findings.
How Rampa was measured on it
| Set | Tests | Cases | axe-core, precision / recall | Rampa, precision / recall / F1 |
|---|---|---|---|---|
| 2.4.6, heading is descriptive (ACT b49b2e) | meaning | 12 | not defined, nothing flagged / 0.00 | 0.80 / 1.00 / 0.89 |
| 2.4.6, field label is descriptive (ACT cc0f0a) | meaning | 16 | not defined, nothing flagged / 0.00 | 1.00 / 0.83 / 0.91 |
Corrupted pairs: Rampa told 8 of 9 apart (headings and labels), axe-core 0. A pair is a passing test page and a copy broken on purpose; a checker that gives both the same verdict is not judging.
Run on 9 October 2026: axe-core 4.14.0, Gemma 4 12B on a local GPU, reasoning off, one run, ACT test cases a9a1483e. Small samples and one run: read the numbers as a working pipeline, not as a result.
Read with these caveats
- The prompts and the context for 2.4.2, 2.4.4 and 2.4.6 were adjusted after reading this run’s errors, without copying the test pages into the prompts. They need fresh pages before the numbers mean more than “the pipeline works”.
- The one pair Rampa did not tell apart is an intact page it also fails: a glossary under the heading “A”.
- Real pages are noisier than test cases. On this project’s own landing page, Gemma flags three short English headings that a person would pass, such as the step name “Collect”, and nothing on the Portuguese page.
Limitations
- In the run recorded for this page, Gemma passed “Shipping” over a paragraph about returns, a miss, and failed “Gift cards” over the gift card form, a false positive. Both happened in English and in Portuguese.
- A heading with nothing under it is skipped, and text that only looks like a heading is not seen: marking headings up is 1.3.1.
- It judges the labels of form fields. The text of buttons and other controls is not judged under 2.4.6.
- The model reads about 700 characters of a section, so a long section is judged on its start.
Questions about 2.4.6
Does WCAG 2.4.6 require headings and labels?
No. It requires the headings and labels you have to describe their topic or purpose. Whether content needs headings or fields need labels is covered by 1.3.1 and 3.3.2, and whether a field’s name is exposed by 4.1.2.
Can a heading be one word?
Yes. Understanding 2.4.6 says a word, or even a single character, may be enough when it gives the right cue. Rampa tells the model the same and still errs: on this project’s own landing page, Gemma flags three short headings a person would pass.
Does axe-core check headings and labels?
No axe-core rule is mapped to 2.4.6. label (mapped to 4.1.2) fails a field with no label at all, and empty-heading, a best practice, fails a heading with no text. A label that says “Field 1” passes both.
Check your pages
Rampa is not on npm yet. Clone it and run it from source with Node.js 22.12 or newer and Chrome or Edge. --criteria 2.4.6 judges only this criterion; leave it out to run the eight that run by default.
With Ollama running, Rampa picks a local model by itself; node dist/cli.mjs doctor says what is missing.
git clone https://github.com/guilhermebsantiago/rampa-cli.git
cd rampa-cli
pnpm install && pnpm build
node dist/cli.mjs check https://example.com --criteria 2.4.6Checked against rampa-cli (commit 0459809) and the W3C sources on 9 October 2026.