Profile

The Storyteller

Minimal musings on code, design, and life


Building Accessible Web Interfaces

By The Storyteller February 28, 2025 Posted in Web Dev
Building Accessible Web Interfaces

Web accessibility isn’t just a nice-to-have feature—it’s a fundamental requirement for creating inclusive digital experiences. When we build accessible interfaces, we create better experiences for everyone, not just users with disabilities.

Why Accessibility Matters

The Numbers

Beyond Compliance

While legal requirements like WCAG 2.1 and ADA compliance are important, accessibility is really about human dignity and equal access to information and functionality.

The Curb-Cut Effect

Accessibility improvements often benefit everyone:

Understanding Different Types of Disabilities

Visual Impairments

Hearing Impairments

Motor Impairments

Cognitive Disabilities

The WCAG Principles: POUR

Web Content Accessibility Guidelines are built on four principles:

1. Perceivable

Information must be presentable in ways users can perceive.

<!-- Bad: Image without alt text -->
<img src="chart.png" />

<!-- Good: Descriptive alt text -->
<img src="chart.png" alt="Sales increased 25% from Q1 to Q2 2024" />

<!-- Good: Decorative image -->
<img src="decoration.png" alt="" role="presentation" />

2. Operable

Interface components must be operable by all users.

/* Ensure focus is visible */
button:focus {
  outline: 2px solid #4a90e2;
  outline-offset: 2px;
}

/* Ensure touch targets are large enough */
button {
  min-height: 44px;
  min-width: 44px;
}

3. Understandable

Information and UI operation must be understandable.

<!-- Clear, descriptive labels -->
<label for="email">
  Email Address (required)
  <input type="email" id="email" required aria-describedby="email-help" />
</label>
<div id="email-help">We'll never share your email with third parties.</div>

4. Robust

Content must be robust enough for various assistive technologies.

<!-- Use semantic HTML -->
<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>

Essential Accessibility Techniques

1. Semantic HTML

Use the right HTML elements for their intended purpose:

<!-- Instead of div soup -->
<div class="header">
  <div class="nav">
    <div class="nav-item">Home</div>
  </div>
</div>

<!-- Use semantic elements -->
<header>
  <nav>
    <a href="/">Home</a>
  </nav>
</header>

2. ARIA (Accessible Rich Internet Applications)

ARIA attributes provide additional context for assistive technologies:

<!-- Button that controls content -->
<button aria-expanded="false" aria-controls="menu" id="menu-button">Menu</button>
<ul id="menu" aria-labelledby="menu-button" hidden>
  <li><a href="/home">Home</a></li>
  <li><a href="/about">About</a></li>
</ul>

<!-- Progress indicator -->
<div role="progressbar" aria-valuenow="32" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">32% complete</div>

3. Keyboard Navigation

Ensure all functionality is accessible via keyboard:

// Handle keyboard events
function handleKeyDown(event) {
  switch (event.key) {
    case "Enter":
    case " ": // Space
      event.preventDefault()
      toggleMenu()
      break
    case "Escape":
      closeMenu()
      break
    case "ArrowDown":
      focusNextItem()
      break
    case "ArrowUp":
      focusPreviousItem()
      break
  }
}

4. Color and Contrast

Ensure sufficient color contrast and don’t rely solely on color:

/* WCAG AA requires 4.5:1 contrast for normal text */
.text {
  color: #333333; /* Dark gray on white background */
  background: #ffffff;
}

/* Don't rely only on color for meaning */
.error {
  color: #d32f2f;
  border-left: 4px solid #d32f2f;
}

.error::before {
  content: "⚠ ";
  font-weight: bold;
}

Form Accessibility

Forms are critical interaction points that need special attention:

<form>
  <!-- Group related fields -->
  <fieldset>
    <legend>Personal Information</legend>

    <!-- Associate labels with inputs -->
    <div class="field">
      <label for="first-name"> First Name * </label>
      <input type="text" id="first-name" name="firstName" required aria-describedby="first-name-error" />
      <div id="first-name-error" class="error" aria-live="polite">
        <!-- Error messages appear here -->
      </div>
    </div>

    <!-- Provide clear instructions -->
    <div class="field">
      <label for="password"> Password </label>
      <input type="password" id="password" aria-describedby="password-help" />
      <div id="password-help">Must be at least 8 characters with one number and one special character.</div>
    </div>
  </fieldset>

  <!-- Clear submit button -->
  <button type="submit">Create Account</button>
</form>

Testing for Accessibility

Automated Testing

Use tools to catch obvious issues:

# Install accessibility linting
npm install --save-dev eslint-plugin-jsx-a11y

# Use automated testing tools
npm install --save-dev @axe-core/playwright
// Example automated test
import { test, expect } from "@playwright/test"
import { injectAxe, checkA11y } from "@axe-core/playwright"

test("should not have accessibility violations", async ({ page }) => {
  await page.goto("/")
  await injectAxe(page)
  await checkA11y(page)
})

Manual Testing

  1. Keyboard-only navigation: Unplug your mouse and navigate using only the keyboard
  2. Screen reader testing: Use NVDA (Windows), JAWS (Windows), or VoiceOver (Mac)
  3. Color blindness simulation: Use browser developer tools
  4. Zoom testing: Test at 200% zoom level

User Testing

Include users with disabilities in your testing process. Their lived experience provides insights that automated tools and guidelines can’t capture.

Common Accessibility Mistakes

1. Missing Alt Text

<!-- Wrong -->
<img src="product.jpg" />

<!-- Right -->
<img src="product.jpg" alt="Blue wireless headphones with noise cancellation" />

2. Poor Focus Management

// When opening a modal, move focus to it
function openModal() {
  modal.style.display = "block"
  modal.querySelector("h2").focus() // Focus the modal title

  // Trap focus within modal
  trapFocus(modal)
}

3. Inaccessible Custom Components

<!-- Don't do this -->
<div class="button" onclick="doSomething()">Click me</div>

<!-- Do this instead -->
<button onclick="doSomething()">Click me</button>

<!-- Or if you must use div -->
<div role="button" tabindex="0" onclick="doSomething()" onkeydown="handleKeyDown(event)">Click me</div>

Advanced Accessibility Patterns

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

<nav>
  <!-- Navigation here -->
</nav>

<main id="main-content">
  <!-- Main content here -->
</main>
.skip-link {
  position: absolute;
  top: -40px;
  left: 6px;
  background: #000;
  color: #fff;
  padding: 8px;
  text-decoration: none;
  transition: top 0.3s;
}

.skip-link:focus {
  top: 6px;
}

Live Regions

<!-- Announce dynamic content changes -->
<div aria-live="polite" id="status">
  <!-- Status updates appear here -->
</div>

<div aria-live="assertive" id="errors">
  <!-- Critical errors appear here -->
</div>
// Announce changes to users
function announceStatusChange(message) {
  document.getElementById("status").textContent = message
}

Mobile Accessibility

Mobile devices have unique accessibility considerations:

/* Ensure touch targets are large enough */
@media (max-width: 768px) {
  button,
  a,
  input {
    min-height: 44px;
    min-width: 44px;
  }

  /* Increase spacing between interactive elements */
  .button-group button + button {
    margin-left: 8px;
  }
}

Performance and Accessibility

Slow-loading sites are accessibility barriers:

<!-- Provide immediate feedback -->
<button aria-describedby="loading-status">Submit</button>
<div id="loading-status" aria-live="polite">
  <!-- "Processing..." appears here when loading -->
</div>

Building an Accessibility-First Culture

1. Education

2. Process Integration

3. Continuous Improvement

Conclusion

Building accessible web interfaces is not just about compliance—it’s about creating inclusive experiences that work for everyone. By incorporating accessibility from the start of your design and development process, you’ll create better products that serve a wider audience.

Remember: accessibility is not a feature you add at the end—it’s a fundamental aspect of good web development. Start with semantic HTML, enhance with ARIA when needed, test with real users, and iterate based on feedback.

The web is for everyone. Let’s build it that way.


You Might Also Like