Accessibility Foundations · 4 / 8
lesson 4

Semantic HTML is accessibility

The first rule of ARIA is: don't. Native elements are doing more for you than you think.

~ 15 min read·lesson 4 of 8
0 / 8

Here's a small secret of accessibility: most of the spec is satisfied not by adding things, but by not removing things. The browser does an enormous amount of work for you when you use the right HTML element. Use the wrong one — say, a <div> styled to look like a button — and you have to recreate every one of those features by hand. Most people don't.

Semantic HTML is HTML where each element matches its meaning: <button> for a button, <nav> for navigation, <h2> for a section heading, <label> for a form label.

The first rule of ARIA

There's a famous line in the ARIA spec: "No ARIA is better than bad ARIA." The W3C even gives this its own catchy name: the first rule of ARIA useif you can use a native HTML element with the role and behavior you want, do that, and don't redefine it with ARIA.

Why? Because ARIA only describes things to assistive tech. It doesn't add behavior. role="button" on a <div> makes a screen reader call it a button. It does not make Enter activate it. It does not put it in the tab order. It does not make Space trigger a click. You have to wire all of that yourself with JavaScript, and most people will do it imperfectly.

A real <button> does all of that automatically. So does <a href>. So does <input>.

Tip

ARIA is a fire extinguisher: useful when you actually need it, completely unnecessary if you didn't start the fire.

What you get for free with native elements

Compare a real button to a fake one:

real.html
<button type="button">Open menu</button>
fake.html
<div class="btn" onclick="open()">Open menu</div>

The real <button> ships with all of these, no extra code:

  • It's announced as "button, Open menu" by every screen reader.
  • It's in the tab order — Tab reaches it.
  • Enter and Space activate it.
  • It has a focus ring you can see.
  • It supports the disabled attribute, which removes it from the tab order and announces "dimmed" or similar.
  • It submits forms (when type is omitted, in a form) or doesn't (type="button").
  • It works with form validation, autofocus, and form-associated APIs.

The fake <div> ships with one thing: a click handler. To match the real button you'd need to add tabindex="0", role="button", an Enter/Space keydown listener, a focus style, an aria-disabled story, and a workaround for forms. You will get one of these wrong.

check your understanding
You're tempted to make a "fancy" button by styling a <div>. Which of these will you not get back, even if you add role="button" and tabindex="0"?

Landmarks and structure

Screen-reader users navigate by landmarks — large named regions of the page. Modern HTML gives you them as elements:

  • <header> — the banner at the top of the page (when it's a top-level header).
  • <nav> — a chunk of navigation links.
  • <main> — the primary content. Exactly one per page.
  • <aside> — sidebars and complementary content.
  • <footer> — the footer (when at the top level).
  • <section> and <article> — generic regions; give them an aria-label or contained heading to make them landmarks.

A user can pull up a list of all landmarks and jump straight to "main" — if you used the element. If your page is a stack of <div class="header">, <div class="content">, <div class="footer">, that user has nothing to jump to and has to wade through the navigation every time.

<header><nav><main><aside><footer>
Landmark elements give the page a navigable skeleton, like signposts on a map.

Headings tell the story

Headings (<h1> through <h6>) are not for making text bigger — they're an outline of the page. Screen readers offer a "list of headings" shortcut that's the equivalent of a table of contents.

The rule of thumb: one <h1> per page, and don't skip levels (don't jump from <h2> to <h4>). You can style headings to look any size you like; just keep the ranks correct.

Watch out

Choosing a heading because it "looks right at this size" is the most common reason heading outlines break. Pick the rank for meaning, then style with CSS.

Forms with real labels

Every form input needs a label. The bulletproof pattern:

form.html
<label for="email">Email address</label>
<input id="email" name="email" type="email" required>

That for / id pairing does three things at once: it tells the screen reader the input's name, it makes clicking the label focus the input (handy on small phones), and it lets browsers do autofill correctly.

Things that are not a real label:

  • Placeholder text. Disappears when typing, often low contrast, often missed by autofill.
  • A <span> next to the input. The screen reader doesn't know they're related.
  • An aria-label when a visible label would have worked. Always prefer a visible label.
check your understanding
You have <input placeholder="Email"> with no <label>. The visual designer says "the placeholder is enough." What's the strongest case against?

Why div soup is the villain

Div soup is a page where almost everything is a <div> or <span>, with class names doing all the meaning: class="button", class="link", class="heading", class="navigation". It looks fine. It clicks fine. It is, accessibility-wise, a wasteland.

A screen-reader user lands on a div-soup page, asks for a list of headings, gets nothing. Asks for a list of landmarks, gets nothing. Tries to tab through, hits unreachable controls. They leave.

The fix isn't a giant refactor — it's a habit. Whenever you reach for <div>, ask:

  • Is this a button? <button>.
  • Is this navigation? <nav>.
  • Is this a section title? <h2> (or whatever level fits).
  • Is this a list of things? <ul><li>.
  • Is this the page's main content? <main>.

You'll write the same CSS, you'll keep the same design — and you'll get a working accessibility tree for free.

check your understanding
You inherit a navbar built as <div class="nav"><div class="link">Home</div>...</div>. The cheapest, highest-impact upgrade is:
check your understanding
Which of these is the weakest reason to prefer <button> over <div role="button">?

Native HTML is your accessibility trust fund. Spend it. Next we'll look at the visual layer — color and contrast.

← prevnext lesson →
KeepLearningcertificate
for completing
Accessibility Foundations
0 of 8 read