Structure, keyboard, and focus
Build a meaningful page outline
Use title, language, landmarks, headings, lists, and regions to make the page navigable.
A long page needs more than one way in. A sighted mouse user scans it and clicks where they want. A screen reader user asks the page for its headings, its landmarks and its lists, and jumps. If the page can’t answer, they read it top to bottom, every time.
Structure is how the page answers. Let’s give the registration page one.
Start with the document itself
Two things sit above the content. The title is the first thing announced when the page loads, and it’s the text in the browser tab and in bookmarks. The lang attribute tells the screen reader which voice and pronunciation rules to use.
The flawed page gets both wrong:
<html>
<head>
<title>Home</title>
</head>
Fix both in one step:
<html lang="en">
<head>
<title>Register: Web Dev Meetup Rome, 14 October 2026</title>
</head>
Now a user with five tabs open knows which one this is. These map to WCAG 2.4.2 Page Titled and 3.1.1 Language of Page, both Level A.
Landmarks and headings
Landmarks are the big areas of the page: header, nav, main, footer, plus any section you give a name. Headings are the outline inside them. The rule I follow: write the outline of the content first, as if it were a table of contents, then pick the elements that express it.
For our page that outline becomes:
<body>
<header>
<nav aria-label="Main">...</nav>
</header>
<main>
<h1>Register for Web Dev Meetup Rome</h1>
<section aria-labelledby="schedule-heading">
<h2 id="schedule-heading">Schedule</h2>
</section>
<section aria-labelledby="register-heading">
<h2 id="register-heading">Your registration</h2>
<h3>Contact details</h3>
<h3>Ticket</h3>
</section>
</main>
<footer>...</footer>
</body>
Notice the heading levels follow nesting, not font size. If h3 looks too big for “Ticket”, fix it in CSS. Never pick h5 because it happens to render smaller. A section with an aria-labelledby pointing at its heading becomes a named region, so it shows up in the landmark list with a useful name.
Check it with the rotor
Turn on VoiceOver and press VO + U to open the rotor. Arrow left and right to switch between lists. On the repaired page you see:
Headings
1 Register for Web Dev Meetup Rome
2 Schedule
2 Your registration
3 Contact details
3 Ticket
Landmarks
banner
navigation, Main
main
region, Schedule
region, Your registration
contentinfo
Every stop has a name that tells you what’s there. On the flawed page the same rotor showed one h4 called “Welcome!” and no landmarks at all, because everything lived inside div elements.
Lists too
The speaker line-up is written as six paragraphs on the flawed page. Wrap it in a ul and VoiceOver announces “list, 6 items” before reading it. That single phrase lets the user decide whether to enter the list or skip past it.
Try this on your own page: open the rotor, read the headings list and ask whether each entry would make sense to someone who has never seen the page. Rename or re-level every one that wouldn’t, and repair every ambiguous landmark stop.
Lesson completed