On this page

Basic web accessibility with HTML

14 min read TextCh. 3 — Semantics and Accessibility

What is web accessibility?

Web accessibility (often abbreviated as a11y) means designing and developing pages that can be used by everyone, including people with visual, auditory, motor, or cognitive disabilities.

According to the World Health Organization, more than 15% of the world's population lives with some form of disability. Making your site accessible is not just a best practice -- in many countries it is a legal requirement.

The 4 principles of accessibility (POUR)

The WCAG are based on four fundamental principles:

  1. Perceivable — Information must be perceivable (see, hear, read)
  2. Operable — The interface must be usable with different devices (keyboard, voice)
  3. Understandable — Content and interface must be comprehensible
  4. Robust — Content must work with different assistive technologies

Alternative text for images

The alt attribute is the primary accessibility tool for images:

<!-- Informative image: describe the content -->
<img src="chart.png" alt="Bar chart showing a 25% increase in sales">

<!-- Decorative image: empty alt -->
<img src="decorative-border.png" alt="">

<!-- Functional image (button/link): describe the action -->
<a href="/home">
  <img src="logo.svg" alt="Go to home page">
</a>

The rule is simple:

  • If the image conveys information, describe that information
  • If the image is decorative, use alt="" (empty, do not omit the attribute)
  • If the image is inside a link or button, describe the action

Heading structure

Headings (<h1> through <h6>) create an outline of the page that screen readers use for navigation. Users can jump between headings as if it were a table of contents:

<h1>HTML Course</h1>
  <h2>Chapter 1: Introduction</h2>
    <h3>What is HTML?</h3>
    <h3>History of HTML</h3>
  <h2>Chapter 2: Basic Elements</h2>
    <h3>Text tags</h3>

Essential rules:

  • Do not skip levels (do not go from <h2> to <h4>)
  • One <h1> per page
  • Headings should reflect the logical hierarchy of the content

Keyboard navigation

Many users navigate exclusively with the keyboard (Tab, Enter, Escape, arrow keys). Make sure that:

All interactive elements are focusable

Native HTML elements like <a>, <button>, <input>, and <select> are focusable by default. If you create interactive elements with <div> or <span>, they will not be focusable unless you add tabindex="0":

<!-- Correct: native button, automatically focusable -->
<button type="button">Open menu</button>

<!-- Incorrect: non-focusable and non-accessible div -->
<div class="button" onclick="openMenu()">Open menu</div>

<!-- Better: always use native elements when possible -->

A "skip link" allows keyboard users to jump directly to the main content without having to tab through the entire navigation:

<body>
  <a href="#main" class="skip-link">Skip to main content</a>
  <nav><!-- many navigation links --></nav>
  <main id="main">
    <!-- main content -->
  </main>
</body>

Accessible forms

Forms are one of the most critical areas for accessibility:

Explicit labels

Every form field must have an associated <label>:

<!-- Explicit association with for/id -->
<label for="username">Username</label>
<input type="text" id="username" name="username">

<!-- Implicit association (label wraps the input) -->
<label>
  Email address
  <input type="email" name="email">
</label>

Additional descriptions with aria-describedby

When a field needs additional instructions:

<label for="password">Password</label>
<input type="password" id="password" aria-describedby="password-req">
<p id="password-req">Minimum 8 characters, include a number and an uppercase letter.</p>

Use <fieldset> and <legend> to group related fields:

<fieldset>
  <legend>Shipping address</legend>
  <label for="street">Street</label>
  <input type="text" id="street" name="street">
  <label for="city">City</label>
  <input type="text" id="city" name="city">
</fieldset>

Essential ARIA attributes

ARIA (Accessible Rich Internet Applications) provides attributes that improve accessibility when native HTML is not sufficient:

Attribute Use
aria-label Accessible name when there is no visible text
aria-labelledby References an element that acts as a label
aria-describedby References an element with additional description
aria-required Indicates that a field is required
aria-hidden Hides an element from assistive technologies
aria-current Indicates the current element in a set (active page, current step)
role Defines the semantic role of an element

The most important ARIA rule: do not use ARIA if you can achieve the same thing with native HTML. A <button> is better than a <div role="button">.

Color contrast

The contrast between text and background must meet the following ratios (WCAG AA):

  • Normal text: minimum ratio of 4.5:1
  • Large text (18px bold or 24px normal): minimum ratio of 3:1
  • Interface elements (borders, icons): minimum ratio of 3:1

Tools like the accessibility inspector in Chrome DevTools allow you to check contrast directly in your browser.

Practice

  1. Add a skip link: Create a page with extensive navigation and add a "Skip to main content" link as the first element of the <body> that points to the id of the <main>.
  2. Build an accessible form: Create a contact form where every <input> has an associated <label> using for/id, at least one field uses aria-describedby for additional instructions, and radio buttons are wrapped in a <fieldset> with <legend>.
  3. Audit your images: Review an existing page and make sure all informative images have a descriptive alt and all decorative images have alt="".

In the next lesson, we will learn how to build complete and functional forms.

WCAG: the accessibility standard
The Web Content Accessibility Guidelines (WCAG) define three levels of conformance (A, AA, AAA). Most laws and standards require at least level AA. Following the practices in this lesson will help you meet that standard.
Common mistakes
The 3 most common accessibility errors are: images without an alt attribute, forms without labels, and insufficient color contrast. These affect the largest number of users with disabilities.
html
<!-- Accessible form -->
<form aria-labelledby="form-title">
  <h2 id="form-title">Contact form</h2>

  <div>
    <label for="full-name">Full name *</label>
    <input
      type="text"
      id="full-name"
      name="full-name"
      required
      autocomplete="name"
      aria-required="true"
    >
  </div>

  <div>
    <label for="email">Email address *</label>
    <input
      type="email"
      id="email"
      name="email"
      required
      autocomplete="email"
      aria-required="true"
      aria-describedby="email-hint"
    >
    <small id="email-hint">Example: [email protected]</small>
  </div>

  <div role="group" aria-labelledby="preference-label">
    <p id="preference-label">Preferred contact method:</p>
    <label>
      <input type="radio" name="contact" value="email"> Email
    </label>
    <label>
      <input type="radio" name="contact" value="phone"> Phone
    </label>
  </div>

  <button type="submit">Send message</button>
</form>
html
<!-- Skip link to jump to content -->
<a href="#main-content" class="skip-link">
  Skip to main content
</a>

<header>
  <nav aria-label="Main menu">
    <ul role="list">
      <li><a href="/" aria-current="page">Home</a></li>
      <li><a href="/courses">Courses</a></li>
      <li><a href="/blog">Blog</a></li>
    </ul>
  </nav>
</header>

<main id="main-content">
  <h1>Welcome to the site</h1>

  <!-- Informative image -->
  <img src="team.jpg"
    alt="Our team of 5 developers at the office"
    width="800" height="450">

  <!-- Decorative image -->
  <img src="decoration.svg" alt="" role="presentation">

  <!-- Icon with alternative text -->
  <button type="button" aria-label="Close dialog">
    <svg aria-hidden="true" focusable="false">
      <!-- X icon -->
    </svg>
  </button>
</main>