Semantic HTML
"Semantic" means "carrying meaning". Semantic HTML uses elements that say what a thing is: a heading, a button, a list. Browsers and screen readers use that meaning. You get a lot of accessibility for free.
In one minute
- Div soup is a page built almost only from
<div>and<span>. It looks fine but means nothing. - Meaningful elements like
<nav>,<h1>,<button>and<ul>come with a role, keyboard support and shortcuts. - Every control has a role (what it is), a name (what it is called) and maybe a state (on, off, open).
- CSS changes how things look. HTML says what things are. A big bold div is still not a heading.
<div>and<span>are fine for layout and styling, when no meaning is needed.
Imagine a bookshop where every box looks the same and has no label. You could still find a book, but only by opening every box. Semantic HTML puts labels on the boxes: "Menu", "Main content", "Heading", "Button". A screen reader reads the labels, so its user can go straight to the right box.
1. The problem: a school portal made of divs
Arjun is blind and uses a screen reader. He opens his school portal to submit homework. The page looks normal, but it is div soup.
Div soup
Bad<div class="top">Green Valley School</div>
<div class="title">My homework</div>
<div class="item">Physics worksheet</div>
<div class="btn" onclick="send()">
Submit homework
</div>
Semantic
Fixed<header>Green Valley School</header>
<main>
<h1>My homework</h1>
<ul><li>Physics worksheet</li></ul>
<button type="button">Submit homework</button>
</main>
With div soup, Arjun cannot jump to the content. He must listen to the whole page, line by line. Then he cannot press the submit "button" at all. He misses the deadline.
- Which single change in the fixed code lets Arjun submit with the keyboard? (Answer:
<div class="btn">became<button>.)
2. What meaningful elements give you for free
A landmark is a big region of the page, like "navigation" or "main". Screen reader users can list landmarks and jump between them. Most screen readers also let users jump from heading to heading (for example, the H key in NVDA and JAWS).
| Element | Announced as | What you get for free |
|---|---|---|
<header> | banner | A landmark for the site's top area. Only when it is not inside main, article, section, aside or nav. |
<nav> | navigation | A landmark for a group of main links. |
<main> | main | A landmark for the page's main content. Use one per page. |
<article> | article | A complete piece that makes sense alone: a post, a product card. |
<section> | region (only if it has a name) | Groups related content. It becomes a landmark only when labelled, for example with aria-labelledby. |
<aside> | complementary | A landmark for side content, like "Related books". |
<footer> | content info | A landmark for the page's bottom area, when not inside another section. |
<h1>–<h6> | heading, level 1–6 | An outline of the page. Users jump by headings. |
<ul>, <ol> | list, 3 items | The item count, so users know how long the list is. |
<table> | table, 5 rows, 4 columns | Moving cell by cell, with row and column headers read out. |
<button> | button | Focus with Tab. Works with Enter and Space. |
<a href> | link | Focus with Tab. Works with Enter. Can open in a new tab. |
<form> + <label> | edit text, "Email" | The label becomes the field's name. Clicking the label focuses the field. |
Step 1. Tick each fix to rebuild the portal. The panels scan the real HTML each time.
Step 2. Press Tab into the demo page. Count the stops.
Show the HTML of the demo page
Landmarks list
Headings list
Lists
Tab stops
- Tick only "Real headings". How many headings appear? Do any landmarks appear? Why not?
3. Role, name and state
Assistive tech asks three questions about every control. What is it? What is it called? What condition is it in?
| Word | Question | Example on a food-delivery app |
|---|---|---|
| Role | What kind of thing is it? | button, link, checkbox, heading |
| Name | What is it called? | "Place order" (from the button's text) |
| State | What condition is it in? | checked, not checked, expanded, collapsed, pressed |
Here is how a screen reader might combine them. The exact words differ between screen readers.
Native elements fill in role, name and state for you. A <div> fills in none of them.
You can add them with ARIA (later lessons), but the first rule of ARIA is: use the real element if one exists.
- For
<input type="checkbox" checked> Veg only, name the role, name and state. (checkbox, "Veg only", checked.)
4. Fake button vs real button
A real <button> is focusable and works with Enter and Space. A div with a click handler only works with a mouse.
Adding tabindex="0" makes the div focusable, but the keys still do nothing.
Step 1. Use only the keyboard. Press Tab to reach each "Add to basket", then press Enter and Space.
Step 2. Watch the counters. Then try the mouse for comparison.
A. <div onclick>
Mouse: 0 · Keyboard: 0
B. <div tabindex="0" onclick>
Mouse: 0 · Keyboard: 0
C. <button>
Mouse: 0 · Keyboard: 0
- Get the keyboard count of C to 2, using Enter once and Space once. Can you get A's keyboard count above 0?
5. Looks are not meaning
CSS decides how something looks. HTML decides what it is. A screen reader ignores size and boldness.
Looks like a heading
Bad<div class="big-bold">Today's specials</div>
Is a heading, styled small
FixedToday's specials
<h2 class="small-caps">Today's specials</h2>
Pick the element for its meaning. Then use CSS to make it look the way you want.
When div and span are fine
- A wrapper only for layout, like a grid or a flex row of cards.
- A hook for styling, like
<span class="price-old">to colour part of a sentence. - When no other element matches the meaning. If the words need stress, use
<em>or<strong>instead.
- A designer wants a small grey line of text above the main title. Is it a heading? (Usually not. Use
<p>and style it.)
6. Pick the right element
Six pieces of a real page. Choose the element that carries the right meaning.
Quiz. Choose one answer per line. You can change your answer.
Common mistakes
| You see | Why it is a problem | Fix |
|---|---|---|
<div onclick> as a button | No focus, no role, no Enter or Space. | <button type="button"> |
Big bold div as a title | Missing from the headings list. | <h1>–<h6>, styled with CSS |
Picking h4 because it is "the right size" | The level tells structure, not size. | Pick the level by structure. Resize with CSS. |
| Menu links in plain divs | No landmark, no item count. | <nav> with <ul> |
Two or more <main> elements shown at once | Users cannot tell which is the real content. | One visible <main> per page. |
<div role="button" tabindex="0"> | You must write all the key handling yourself. | Use <button>. |
- Right-click a page you use and choose "Inspect". Count the
divs. Find one that should be abutton,navor heading. - In your browser's developer tools, open the Accessibility panel. Click a button and read its role and name.
- In lab 1, tick the fixes one at a time. Which fix adds the most to the screen reader's lists?
Remember
- Choose elements for their meaning, not their looks.
- Native elements give role, name, state and keyboard support for free.
- Landmarks (
header,nav,main,footer) and headings let users jump around. - Acts →
<button>. Goes somewhere →<a href>. divandspanare for layout and styling only.