UX Design

Semantic HTML as the Accessibility Foundation: Why Structure Comes Before ARIA

By EZUD Published · Updated

Semantic HTML as the Accessibility Foundation: Why Structure Comes Before ARIA

The first rule of ARIA is: do not use ARIA if you can use a native HTML element or attribute instead. Native HTML elements carry built-in accessibility — keyboard interactivity, screen reader announcements, and predictable behaviors — that ARIA can only approximate. Yet developers routinely reach for <div> with role="button" instead of <button>, or <span> with role="link" instead of <a>. Understanding what semantic HTML provides for free is the foundation of every accessible interface.

What “Semantic” Means for Accessibility

Semantic HTML means using elements for their intended purpose. Each HTML element carries an implicit role, state, and behavior that assistive technologies depend on:

HTML ElementImplicit RoleBuilt-in Behavior
<button>buttonFocusable, activated by Enter and Space, click event
<a href="...">linkFocusable, activated by Enter, navigates
<input type="checkbox">checkboxFocusable, toggled by Space, checked state
<select>listboxFocusable, arrow key navigation, option selection
<h1><h6>heading (level 1-6)Heading navigation in screen readers
<nav>navigationLandmark navigation in screen readers
<main>mainLandmark navigation, skip target
<table>tableCell-by-cell navigation, header association

When you use a <div> or <span>, the element has no role, no keyboard behavior, and no screen reader announcement. You must manually recreate everything the native element provides — and you will almost certainly miss something.

The Cost of Fake Semantics

The <div> Button

<!-- Inaccessible -->
<div class="btn" onclick="handleClick()">Submit</div>

What is missing:

  1. No keyboard focus: Users cannot Tab to it. Fix: add tabindex="0".
  2. No keyboard activation: Enter and Space do nothing. Fix: add a keydown handler for Enter and Space.
  3. No role: Screen readers announce “Submit” with no context. Fix: add role="button".
  4. No form participation: Will not submit a form on Enter. Fix: complex JavaScript workaround.
  5. No disabled state: disabled attribute does nothing on divs. Fix: aria-disabled="true" plus CSS plus preventing click events.
<!-- "Fixed" but fragile -->
<div class="btn" role="button" tabindex="0" onclick="handleClick()" onkeydown="if(event.key==='Enter'||event.key===' '){handleClick()}">
  Submit
</div>

Compare with the native element:

<!-- Accessible by default -->
<button onclick="handleClick()">Submit</button>

One line. Keyboard focus, activation, role, form participation, and disabled state all work natively.

<!-- Inaccessible -->
<span class="link" onclick="navigate('/about')">About Us</span>

Missing: focus, keyboard activation, link role, right-click context menu, middle-click new tab, link styling, link discovery by screen readers. The native alternative:

<a href="/about">About Us</a>

The <div> Checkbox

Custom-styled checkboxes built from <div> elements lack checked state management, label association, form participation, and the Space key toggle. The accessible approach is to style the native <input type="checkbox"> using modern CSS techniques that hide the native checkbox visually while preserving its functionality.

Semantic Elements for Page Structure

Landmarks

HTML5 introduced semantic sectioning elements that create landmark regions automatically:

  • <header> (top-level) maps to banner
  • <nav> maps to navigation
  • <main> maps to main
  • <aside> maps to complementary
  • <footer> (top-level) maps to contentinfo
  • <section> with an accessible name maps to region

Screen reader users navigate by landmark to jump between page sections. Without these elements, the page is an undifferentiated block of content.

Headings

Heading elements (<h1> through <h6>) create the page outline. Screen reader users navigate by heading more than any other method — pressing H in NVDA jumps to the next heading, and the elements list shows all headings as a navigable tree.

A page with no heading elements forces screen reader users to read linearly from top to bottom. A page with a clear heading hierarchy lets users jump directly to the section they need.

Lists

<ul>, <ol>, and <dl> communicate grouping and relationship:

  • Screen readers announce “list, 5 items” when entering a list, giving users an immediate sense of scope
  • Ordered lists communicate sequence
  • Description lists (<dl>, <dt>, <dd>) communicate term-definition pairs

A set of links in a <div> with <br> separators gives screen readers no grouping context. The same links in a <ul> are immediately understood as a related set.

Forms

Native form elements provide the most significant accessibility value:

Label Association

<label for="email">Email address</label>
<input type="email" id="email" required />

The <label> element creates a programmatic association — screen readers announce the label when the input receives focus. Clicking the label focuses the input, expanding the interactive target. No ARIA is needed.

Input Types

HTML5 input types (email, tel, url, number, date, search) provide:

  • Appropriate virtual keyboard on mobile devices
  • Built-in validation patterns
  • Screen reader type announcements (“email edit text”)
  • Browser auto-fill support

Required and Validation

The required attribute communicates to screen readers that a field must be filled. The pattern attribute provides client-side validation. The :invalid and :valid CSS pseudo-classes enable styling. These are free with native HTML.

Fieldset and Legend

Group related form controls with <fieldset> and <legend>:

<fieldset>
  <legend>Shipping Address</legend>
  <label for="street">Street</label>
  <input id="street" type="text" />
  <!-- More address fields -->
</fieldset>

Screen readers announce the legend as context for each field within the fieldset: “Shipping Address, Street, edit text.” This grouping is essential for complex forms like multi-step wizards.

When ARIA Is Necessary

ARIA is necessary when no native HTML element provides the needed semantics:

  • Tabs: No native tab element exists, so role="tablist", role="tab", and role="tabpanel" are needed
  • Combobox: The search autocomplete pattern requires role="combobox" because no native element combines text input with suggestion list
  • Tree view: Hierarchical lists with expand/collapse need role="tree" and role="treeitem"
  • Live regions: aria-live communicates dynamic content changes that no native element handles
  • States: aria-expanded, aria-selected, aria-pressed, and aria-current communicate widget states that have no HTML equivalent

The pattern should be: HTML first, ARIA to fill gaps, JavaScript to manage behavior. If you find yourself adding more than one or two ARIA attributes to an element, reconsider whether a different HTML element would serve better.

Common Anti-Patterns

  1. Redundant ARIA: <button role="button"> adds nothing. The <button> already has the button role. Remove the redundant attribute.
  2. ARIA without behavior: role="button" on a <div> without keyboard handling creates a worse experience than no ARIA — the screen reader announces “button” but the element does not behave like one.
  3. Overriding native semantics: <h2 role="button"> strips the heading role and replaces it with button. Use a button inside the heading: <h2><button>Section Title</button></h2>.
  4. aria-label on non-interactive elements: Screen readers may ignore aria-label on <div> and <span> elements without a role. Use aria-label on interactive elements and landmarks.

Testing Semantic HTML

  • Disable CSS: View the page without styles. The content should be readable and logically ordered based on the HTML structure alone.
  • Heading outline: Use the HeadingsMap browser extension to view the heading hierarchy. It should form a logical table of contents.
  • Landmark list: Use a screen reader’s landmark list. All major page sections should appear.
  • Tab through the page: Every interactive element should receive focus in a logical order without any custom tabindex values.

Key Takeaways

Semantic HTML is not a best practice — it is the prerequisite. Native HTML elements provide keyboard interactivity, screen reader announcements, form participation, and predictable behaviors that ARIA can only partially replicate. Use <button> for buttons, <a> for links, <input> for form fields, landmarks for page structure, and headings for content hierarchy. Reach for ARIA only when no native element serves the purpose. The most accessible codebase is often the one with the least ARIA — because it uses HTML as intended.

Sources