Back to BlogEngineering

Building Accessible Web Applications from Day One

Practical accessibility patterns for React applications — semantic HTML, keyboard navigation, screen readers, and automated testing.

Emily Nakamura Nov 15, 2025 10 min read
Accessibility WCAG React Inclusive Design
Building Accessible Web Applications from Day One

Web accessibility isn't just about compliance — it's about building products that everyone can use. 15% of the world's population has some form of disability. Accessible design benefits everyone: keyboard navigation helps power users, captions help people in noisy environments, high contrast helps users in bright sunlight. At Vaarak, accessibility is a design and engineering standard, not an afterthought.

Inclusive design and accessibility
Accessibility is not a feature — it's a quality attribute that should be present in everything you build

Start with Semantic HTML

The single most impactful accessibility practice is using semantic HTML elements. Screen readers, keyboard navigation, and assistive technologies all rely on semantic structure. A <button> has built-in keyboard support, focus management, and screen reader announcements. A <div onClick> has none of these.

// ✗ Inaccessible: div with onClick, no keyboard support, no screen reader announcement
<div className="btn" onClick={handleSubmit}>Submit</div>

// ✓ Accessible: semantic button with all built-in behaviors
<button type="submit" onClick={handleSubmit}>Submit</button>

// ✗ Inaccessible: generic divs for navigation
<div className="nav"><div className="link">Home</div></div>

// ✓ Accessible: semantic nav, list, and anchor elements
<nav aria-label="Main navigation">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
  </ul>
</nav>

Keyboard Navigation

Every interactive element must be operable with a keyboard alone. This means: focusable elements for all controls, visible focus indicators, logical tab order, and keyboard shortcuts for complex interactions. A good test: can you navigate your entire application without a mouse?

  • Tab: Move between focusable elements. Shift+Tab: Move backwards.
  • Enter/Space: Activate buttons and links. Enter submits forms.
  • Arrow keys: Navigate within components (tabs, menus, radio groups).
  • Escape: Close modals, dropdowns, and popups. Return focus to the trigger element.
  • Never remove focus outlines. Instead, style them to match your design system: outline: 2px solid var(--color-focus-ring).

ARIA: Use Sparingly, Test Thoroughly

ARIA attributes add accessibility semantics that HTML alone can't express. But the first rule of ARIA is: don't use ARIA if native HTML can do the job. ARIA can easily make things worse — a misused aria-label or role can confuse screen readers more than no ARIA at all.

Install a screen reader and use your application with it. VoiceOver (Mac), NVDA (Windows, free), or TalkBack (Android) will reveal issues that no automated tool can catch. Even 10 minutes of screen reader testing per feature prevents major accessibility gaps.

Automated Accessibility Testing

Automated testing catches about 30% of accessibility issues — but it's the easiest 30%. Integrate axe-core into your test suite and CI pipeline. It catches missing alt text, insufficient color contrast, missing form labels, and other WCAG violations automatically.

tests/accessibility.test.ts
import { axe, toHaveNoViolations } from 'jest-axe';
import { render } from '@testing-library/react';

expect.extend(toHaveNoViolations);

test('LoginForm has no accessibility violations', async () => {
  const { container } = render(<LoginForm />);
  const results = await axe(container);
  expect(results).toHaveNoViolations();
});

Accessibility is an ongoing practice. Include it in your definition of done, test it in code reviews, and make it a standard part of your QA process. An accessible application is a better application for everyone.

E

Emily Nakamura

Design Systems Lead