frontend / accessibility / 02_semantic_html_and_landmarks.md

Semantic HTML and Landmarks

4 min read source

Semantic HTML and Landmarks

TL;DR

Semantic HTML is ~80% of accessibility for free. Native elements (<button>, <a>, <nav>, <main>, <h1><h6>, <label>, <table>) come with the correct role, keyboard behavior, focusability, and states that assistive tech relies on. A <div onClick> has none of that. Use the right element first; reach for ARIA only to fill genuine gaps. Landmarks (header, nav, main, aside, footer) let screen-reader users jump between page regions; a logical heading hierarchy is how they skim.

Interview Q&A

Q: Why prefer <button> over <div onClick>?

A: A native <button> is, for free:

  • focusable (in the tab order) — a <div> is not without tabindex="0",
  • operable by keyboard — Enter/Space activate it; a <div> needs manual keydown handling,
  • announced as “button” with its label by screen readers — a <div> is announced as nothing,
  • equipped with disabled semantics and form participation.

To match a <button> with a <div> you’d need role="button", tabindex="0", and key handlers for Enter and Space — and you’d still miss edge cases. Just use <button>.

Q: What are landmarks and why do they matter?

A: Landmark elements define page regions that screen-reader users navigate between directly (e.g., “jump to main”):

Element Role Purpose
<header> banner (when top-level) site header
<nav> navigation navigation blocks
<main> main the primary content (one per page)
<aside> complementary tangential content
<footer> contentinfo (top-level) site footer
<section> with a name region named significant area
<form> with a name form a form region

Use one <main>. Give repeated landmarks accessible names (<nav aria-label="Primary">, <nav aria-label="Footer">) so users can tell them apart.

Q: How should headings be structured?

A: One <h1> describing the page, then a logical, non-skipping hierarchy (h1 → h2 → h3, don’t jump h2→h4). Headings are the screen-reader equivalent of skimming — users list and jump by heading. Don’t pick a heading level for its font size (style with CSS); pick it for document structure.

Q: When is a <div>/<span> the right choice?

A: For styling/layout containers with no semantic meaning. <div> and <span> have no implicit role, which is correct when the element is purely presentational. Problems arise only when you put behavior (click handlers, “buttons,” “links”) on them.

Q: What semantic elements are commonly under-used?

A: <button type="button"> (vs div), <a href> for navigation (vs button/div with JS), <label> tied to inputs, <fieldset>/<legend> for groups, <table> with <th scope> for tabular data, <ul>/<ol>/<li> for lists, <nav>/<main>/<aside>, <details>/<summary> for native disclosure, <dialog> for modals, <time>, <figure>/<figcaption>. Each carries semantics ARIA would otherwise have to fake.

Q: <button> vs <a> — when each?

A: <a href> navigates (changes URL / location) and should be a link. <button> performs an action in place (submit, toggle, open menu). Misusing them breaks expectations: links open in new tabs, are bookmarkable, and respond to Enter; buttons respond to Enter and Space and aren’t navigable destinations. A “link” with role="button" is usually a sign you picked the wrong element.

Gotchas / edge cases

  • tabindex > 0 is an anti-pattern — it jumps the element ahead of natural order and creates confusing focus. Use 0 (in natural order) or -1 (focusable only programmatically).
  • role="presentation"/aria-hidden on interactive elements removes them from the a11y tree but they remain keyboard-focusable — a trap. Don’t hide focusable things.
  • Headings used for size produce nonsense outlines for screen readers — keep level = structure, size = CSS.
  • Multiple <main> or <h1> confuses landmark/heading navigation.
  • Generic link text (“click here”, “read more” ×10) is useless out of context — screen-reader users list links; make them self-describing.
  • <section> without an accessible name is not exposed as a landmark — name it or use a plain element.

What a senior is expected to say

  • “Semantic HTML gives role, keyboard behavior, focusability, and state for free — <div onClick> gives none. Right element first, ARIA only for gaps.”
  • “Landmarks let screen-reader users jump between regions; one <main>, named duplicate <nav>s.”
  • “Headings are document structure for skimming — level by meaning, size by CSS, no skipped levels.”
  • <a> navigates, <button> acts; positive tabindex is an anti-pattern.”

Cross-references

Further reading