~/hackweb.dev
HTML Accessibility (ARIA Basics)
Quiz
...

HTML Accessibility (ARIA Basics)

beginner · updated Tue Sep 08 2026Contribute

Learn ARIA roles, labels, and screen reader basics for accessible websites.

HTML Accessibility (ARIA Basics)

Accessibility ensures everyone can use your website — including people with disabilities. ARIA (Accessible Rich Internet Applications) helps bridge gaps when HTML alone isn’t enough.

Why Accessibility?

  • Legal requirement — Many countries mandate accessibility
  • Better SEO — Search engines read accessible code
  • Wider audience — 15% of people have disabilities
  • Better UX — Accessible sites work better for everyone

Semantic HTML First

Always use semantic HTML before ARIA:

<!-- Bad: Using div with ARIA -->
<div role="button" tabindex="0" onclick="handleClick()">
  Click me
</div>

<!-- Good: Using native HTML -->
<button onclick="handleClick()">Click me</button>

Why? Semantic HTML has built-in accessibility. ARIA is a supplement, not a replacement.

ARIA Roles

Roles define what an element is or does:

<!-- Landmark roles -->
<div role="banner">Header content</div>
<div role="navigation">Nav links</div>
<div role="main">Main content</div>
<div role="contentinfo">Footer content</div>

<!-- Widget roles -->
<div role="button">Custom button</div>
<div role="tab">Tab item</div>
<div role="tabpanel">Tab content</div>
<div role="alert">Important message</div>

Common roles:

  • banner — Site header
  • navigation — Nav links
  • main — Main content
  • contentinfo — Footer
  • complementary — Sidebar
  • search — Search functionality
  • button — Interactive button
  • tab — Tab interface
  • tabpanel — Tab content
  • alert — Important messages
  • dialog — Modal dialog
  • progressbar — Progress indicator

ARIA Labels

Labels describe elements for screen readers:

aria-label

Provides an accessible name:

<button aria-label="Close menu">×</button>

<nav aria-label="Main navigation">
  <ul>
    <li><a href="/">Home</a></li>
  </ul>
</nav>

<nav aria-label="Footer navigation">
  <ul>
    <li><a href="/privacy">Privacy</a></li>
  </ul>
</nav>

aria-labelledby

References another element’s text:

<h2 id="section-title">Our Services</h2>
<div aria-labelledby="section-title">
  <p>Service content here...</p>
</div>

aria-describedby

Provides additional description:

<label for="password">Password</label>
<input type="password" id="password" aria-describedby="password-help" />
<span id="password-help">Must be at least 8 characters</span>

ARIA States

States change based on user interaction:

aria-expanded

Indicates if something is open/closed:

<button aria-expanded="false" onclick="toggleMenu()">
  Menu
</button>

<button aria-expanded="true" onclick="toggleMenu()">
  Menu
</button>

aria-hidden

Hides elements from screen readers:

<!-- Decorative icon - hide from screen readers -->
<span aria-hidden="true">🎨</span>

<!-- Hide content visually but keep accessible -->
<div aria-hidden="true" style="display: none;">
  This is hidden from everyone
</div>

aria-live

Announces dynamic content changes:

<!-- Polite announcement (waits for user to finish) -->
<div aria-live="polite">New message received</div>

<!-- Assertive announcement (interrupts immediately) -->
<div aria-live="assertive">Error occurred!</div>

aria-disabled

Indicates element is disabled:

<button aria-disabled="true" disabled>Can't click me</button>

Complete Example

Here’s an accessible navigation and content example:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Accessible Page</title>
  </head>
  <body>
    <!-- Header -->
    <header role="banner">
      <h1>My Accessible Site</h1>

      <!-- Main Navigation -->
      <nav aria-label="Main navigation">
        <ul>
          <li><a href="/" aria-current="page">Home</a></li>
          <li><a href="/about">About</a></li>
          <li><a href="/contact">Contact</a></li>
        </ul>
      </nav>
    </header>

    <!-- Main Content -->
    <main role="main">
      <h2>Welcome</h2>

      <!-- Accessible Form -->
      <form>
        <div>
          <label for="name">Name (required)</label>
          <input
            type="text"
            id="name"
            name="name"
            required
            aria-required="true"
          />
        </div>

        <div>
          <label for="email">Email (required)</label>
          <input
            type="email"
            id="email"
            name="email"
            required
            aria-required="true"
            aria-describedby="email-help"
          />
          <span id="email-help">We'll never share your email</span>
        </div>

        <button type="submit">Submit</button>
      </form>

      <!-- Accessible Alert -->
      <div role="alert" aria-live="assertive" id="form-status">
        <!-- Status messages appear here -->
      </div>
    </main>

    <!-- Footer -->
    <footer role="contentinfo">
      <nav aria-label="Footer navigation">
        <ul>
          <li><a href="/privacy">Privacy Policy</a></li>
          <li><a href="/terms">Terms of Service</a></li>
        </ul>
      </nav>
      <p>&copy; 2026 My Site</p>
    </footer>

    <script>
      // Show status message
      function showStatus(message) {
        const status = document.getElementById('form-status');
        status.textContent = message;
      }
    </script>
  </body>
</html>

Keyboard Navigation

Ensure all interactive elements are keyboard accessible:

<!-- Custom button with keyboard support -->
<div
  role="button"
  tabindex="0"
  onclick="handleClick()"
  onkeydown="if(event.key==='Enter'||event.key===' ')handleClick()"
>
  Click me
</div>

<!-- Skip link for keyboard users -->
<a href="#main-content" class="skip-link">
  Skip to main content
</a>

<style>
  .skip-link {
    position: absolute;
    top: -40px;
    left: 0;
    background: #000;
    color: white;
    padding: 8px;
    z-index: 100;
  }

  .skip-link:focus {
    top: 0;
  }
</style>

ARIA Best Practices

  1. Use semantic HTML first — ARIA is a supplement
  2. Test with screen readers — NVDA, VoiceOver, JAWS
  3. Provide labels — All interactive elements need names
  4. Use live regions — For dynamic content updates
  5. Don’t hide focusable elements — Breaks keyboard navigation

Common Mistakes

  1. Using ARIA instead of HTML — Use <button> not role="button"
  2. Missing labels — Inputs without labels hurt accessibility
  3. Using aria-hidden on focusable elements — Breaks keyboard nav
  4. Not testing with screen readers — Always test real usage
  5. Overusing aria-live — Too many announcements annoy users