IAnswerable

Semantic HTML Is the Cheapest Accessibility Win

05 Nov 2026

Every div you use instead of the element that actually matches your intent is work you’re signing up to redo by hand. Semantic HTML gives you keyboard support, screen reader announcements, and sensible default behavior for free. div soup gives you none of it, and you end up rebuilding all of it in JavaScript.

The elements doing work for you

button gets focusability, Enter/Space activation, and a default role of “button” announced to screen readers — automatically.

<!-- Free: focus, keyboard activation, correct semantics -->
<button>Save</button>

<!-- Costs you: tabindex, keydown handler for Enter AND Space,
     role="button", and you'll probably still miss an edge case -->
<div class="btn" onclick="save()">Save</div>

a href gets keyboard focus, Enter activation, right-click “open in new tab,” middle-click “open in background tab,” and “copy link address” — all free, none of it reproducible in JS without real effort, and some of it (like the browser’s own history integration) not fully reproducible at all.

select gets a native, platform-correct dropdown — touch-friendly on mobile, keyboard-typeable (type “m” to jump to the first option starting with M), no JS required.

<select>
  <option value="us">United States</option>
  <option value="ca">Canada</option>
</select>

A custom-styled dropdown built from divs can look nicer, but now you own the keyboard handling, the typeahead, the mobile behavior, and the ARIA — for a feature the browser already had.

details/summary gets you a working accordion with zero JavaScript:

<details>
  <summary>What's your refund policy?</summary>
  <p>Full refund within 30 days.</p>
</details>

Click or Enter on the summary toggles it. Screen readers announce “expanded” or “collapsed” automatically. This one surprises people the most — most FAQ accordions on the web are a hundred lines of JS reimplementing what this does out of the box.

The table people avoid and shouldn’t

table has a bad reputation from 2005-era layout tables, but for actual tabular data — pricing tiers, comparison grids, data exports — it’s still correct, and it comes with screen reader navigation (jump cell to cell, hear row/column headers announced) that a CSS Grid of divs doesn’t give you unless you hand-roll role="table", role="row", role="cell" and get every one of them right.

<table>
  <thead>
    <tr><th>Plan</th><th>Price</th></tr>
  </thead>
  <tbody>
    <tr><td>Basic</td><td>$9/mo</td></tr>
  </tbody>
</table>

Use Grid or Flexbox for visual layout. Use table when the content is actually tabular data.

The pattern

Before reaching for div plus a class plus a role attribute plus a JS behavior, check whether an element already does that job. The question isn’t “can I style a div to look like this” — you always can. It’s “does a native element already have this behavior,” because if it does, you get correctness for free and div soup gets you a maintenance burden you’ll pay down one bug report at a time.

When div is actually correct

Generic layout containers with no semantic meaning — a wrapper for centering content, a grid container — are exactly what div is for. The rule isn’t “avoid div,” it’s “don’t use div for something that has a real semantic element.” Structure gets a real element. Layout wrapping gets a div. Keep those two decisions separate and most of your markup sorts itself out.