Structuring documents
Every component sits on a page, and the page is a document. Three tiny settings decide whether that document works for everyone: the language, the title, and whether zoom is allowed. They are accessibility, not boilerplate.
In one minute
- Language:
<html lang="en">. A screen reader picks its voice and pronunciation from it. - Title: a unique
<title>per page, specific part first: "Checkout · Northwind". - Viewport: never use
user-scalable=noormaximum-scale=1. Let people zoom. - Order: the first HTML response should hold the real content, and the source order is the reading order.
Think of a book. The cover title tells you which book it is, the language on the spine tells you if you can read it, and the pages are printed in an order that makes sense. The browser needs the same three things before it can hand your page to a person using a screen reader or a magnifier.
1. Set the language, and mark the exceptions
Put a BCP 47 language tag on <html lang>. A screen reader is software that reads the page aloud. It uses
lang to pick a voice. With the wrong language it reads words with the wrong accent, or spells them out. A German
sentence on an English page gets lang="de" on that element only. This is WCAG 3.1.1 (page language) and 3.1.2 (parts).
Step 1. Choose how the markup is written for the sentence below.
- Use the short tag (
en,de). Add a region (en-GB) only when the dialect changes meaning. - Words that have settled into the page language (taxi, pizza, kindergarten in English) do not need a switch.
- Also helps: browser translation, hyphenation, spell check and correct quote marks.
2. Name the document with the title
The <title> is the label of the browser tab, and often the first thing a screen reader says when a page loads.
Put the specific page first and the site second: "Checkout · Northwind". A single title of "Home" or "App" on every route is a bug
(WCAG 2.4.2 Page Titled).
Step 1. Type a title for the checkout page.
Single-page apps change the page without a reload, so they must update document.title on every route change, or users never hear
that the page changed. Lesson 08 covers moving focus too.
3. Viewport: let people zoom
The viewport meta tag tells phones how wide the page is. Two common values switch zoom off:
user-scalable=no and maximum-scale=1. People with low vision rely on pinch zoom and browser zoom.
Blocking it fails WCAG 1.4.4 (Resize Text) and 1.4.10 (Reflow). Try to enlarge the text below.
Step 1. Choose the viewport tag, then press Zoom in.
Delivery slots open at 9:00. Choose one before 17:00.
The standard safe tag is <meta name="viewport" content="width=device-width, initial-scale=1">.
4. Source order is reading order
The accessibility tree (the simplified copy of the page that assistive technology reads) follows the source order, not the
order you painted with CSS. The Tab key does too. If you reverse items visually with flex-direction: row-reverse or order,
keyboard focus jumps around the screen (WCAG 1.3.2 Meaningful Sequence, 2.4.3 Focus Order).
Step 1. Choose the layout, click into the row, then press Tab through the buttons.
Focus order: (press Tab)
Reordering is fine when the order still makes sense. Fix it in the HTML, not with a positive tabindex, which creates a second, hidden order.
5. Put real content in the first HTML
A client-only app can send an empty <body> and build everything with JavaScript. If the script is slow, fails, or the user
has a simple reader mode, there is nothing to read. If you must hydrate, send the primary text in the first response.
Step 1. Pick what the server sends, and imagine the script has not run.
Common mistakes
| You see | Why it is a problem | Fix |
|---|---|---|
No lang, or lang="en" on a German page | Wrong voice and pronunciation. | Correct lang on html and on foreign passages. |
<title>App</title> on every route | Tabs and history are indistinguishable. | Specific title first, site name second. |
user-scalable=no | Low vision users cannot zoom. | Remove it and maximum-scale. |
| Empty body until JS runs | Nothing to read if scripts fail. | Render primary text on the server. |
| CSS reorders focusable items | Focus jumps around the screen. | Change the HTML order instead. |
- View source on this page. Confirm
lang, a uniquetitle, and a viewport that does not disable zoom. - Disable JavaScript in devtools and reload a site you build. Is the main content still there?
- Open five tabs of your app. Can you tell them apart by title alone?
Remember
langon html, and on passages in another language.- A unique, specific
titleper page and per route. - Never block zoom.
- Source order is reading order and focus order.