Ideas Engineered for Tomorrow
We Engineer Services & Solutions for Your Business Needs
Home About
Products
Services
Hire
Industries
Consulting
Partners
Articles Careers Contact
Software Development

Web Accessibility (WCAG): Building Inclusive Applications

1.3 billion people live with some form of disability. Accessible design isn't charity — it's better engineering that helps every user.

February 27, 2026 13 min read
In this article

Web accessibility isn't about compliance checkboxes. It's about building interfaces that work for everyone — including the 15% of the global population with disabilities, users on slow connections, people using their phone one-handed, and anyone who's ever tried to use a website in bright sunlight.

At Pillai Infotech, we learned this the hard way. A client's e-commerce site was losing 12% of checkout completions because the payment form was unusable with screen readers. Fixing accessibility didn't just help disabled users — it improved the experience for everyone and increased conversions by 8%.

Why Accessibility Matters More Than Ever

The Business Case

  • Legal risk is real. Web accessibility lawsuits hit 4,600+ in the US in 2025 alone. The EU's European Accessibility Act takes effect in June 2025, covering all digital products sold in Europe.
  • Market size. 1.3 billion people worldwide have significant disabilities. That's a market larger than China. Add temporary and situational disabilities (broken arm, holding a baby, noisy environment) and you're talking about every user at some point.
  • SEO boost. Accessible sites rank better. Semantic HTML, alt text, heading hierarchy, and fast load times are both accessibility features and SEO signals. Google explicitly considers page experience metrics that overlap with accessibility.

The Engineering Case

Accessible code is usually better code. When you build with semantic HTML, proper labels, and keyboard support, you get:

  • Easier automated testing (proper labels = easy selectors)
  • Better mobile experience (touch targets, readable text)
  • Improved performance (semantic HTML is lighter than div soup)
  • Fewer bugs (proper state management for interactive elements)

WCAG 2.2 Conformance Levels

WCAG organizes requirements into three conformance levels. Understanding which level you need prevents both under-engineering and over-engineering.

Level What It Means Who Needs It Effort
AMinimum — removes biggest barriersBare minimum for any public siteLow
AAStandard — good experience for most usersLegal standard in most jurisdictions. Aim here.Moderate
AAAEnhanced — highest accessibilityGovernment, healthcare, educationHigh

Our recommendation: Target WCAG 2.2 Level AA. It's the legal standard in most countries, covers the vast majority of accessibility needs, and is achievable without excessive effort if you bake it into your development process from the start.

WCAG 2.2 (released October 2023) added 9 new success criteria, including minimum target size for touch (24x24px), focus appearance requirements, and accessible authentication (no cognitive function tests for login). If you were WCAG 2.1 compliant, check the new criteria.

Semantic HTML: The Foundation You're Probably Skipping

Before reaching for ARIA attributes, fix your HTML. Semantic elements give you accessibility for free — screen readers, keyboard navigation, and browser features that just work.


<div class="header">
  <div class="nav">
    <div class="nav-item" onclick="navigate('/about')">About</div>
  </div>
</div>
<div class="main">
  <div class="title">Our Services</div>
  <div class="btn" onclick="submit()">Submit</div>
</div>


<header>
  <nav aria-label="Main navigation">
    <a href="/about">About</a>
  </nav>
</header>
<main>
  <h1>Our Services</h1>
  <button type="submit">Submit</button>
</main>

The semantic version gives you:

  • Landmarks — screen readers can jump between header, nav, main, footer
  • Keyboard support<a> and <button> are focusable and activatable by default
  • Heading hierarchy — screen readers can navigate by heading level
  • Form semantics<button type="submit"> works with Enter key automatically

The Heading Hierarchy Rule

Headings must follow a logical order: H1 → H2 → H3. Never skip levels (H1 → H3). Think of it like a document outline — screen reader users navigate by headings the way sighted users scan a page visually.


<h1>Web Development Services</h1>
<h3>Frontend Development</h3>  
<h4>React Applications</h4>


<h1>Web Development Services</h1>
  <h2>Frontend Development</h2>
    <h3>React Applications</h3>
    <h3>Vue Applications</h3>
  <h2>Backend Development</h2>
    <h3>Node.js APIs</h3>

ARIA: Powerful but Dangerous

ARIA (Accessible Rich Internet Applications) lets you add accessibility information to custom widgets. But the first rule of ARIA is: don't use ARIA if a native HTML element does the job.

When ARIA Is Necessary

  • Custom widgets — tabs, accordions, modals, comboboxes that HTML doesn't provide natively
  • Dynamic content — live regions that announce updates to screen readers
  • Relationships — connecting labels to controls, describing errors

Common ARIA Patterns


<div aria-live="polite" aria-atomic="true">
  3 items in your cart
</div>


<div role="dialog" aria-modal="true"
     aria-labelledby="modal-title">
  <h2 id="modal-title">Confirm Deletion</h2>
  <p>This action cannot be undone.</p>
  <button>Delete</button>
  <button>Cancel</button>
</div>


<div role="tablist" aria-label="Account settings">
  <button role="tab" aria-selected="true"
          aria-controls="panel-1" id="tab-1">
    Profile
  </button>
  <button role="tab" aria-selected="false"
          aria-controls="panel-2" id="tab-2">
    Security
  </button>
</div>
<div role="tabpanel" id="panel-1"
     aria-labelledby="tab-1">
  Profile content here...
</div>
Common mistake: Adding role="button" to a <div> doesn't make it a button. You still need tabindex="0", keyboard event handlers (Enter and Space), and focus styling. Just use <button> — you get all of this free.

Keyboard Navigation: The Most Overlooked Requirement

Every interactive element must be usable with a keyboard alone. This helps screen reader users, power users, people with motor impairments, and anyone whose mouse just died.

Essential Keyboard Patterns

  • Tab — moves focus to the next interactive element
  • Shift+Tab — moves focus backward
  • Enter/Space — activates buttons and links
  • Escape — closes modals, dropdowns, popups
  • Arrow keys — navigates within widgets (tabs, menus, radio groups)

Focus Management

/* Visible focus indicator — REQUIRED */
/* Never use outline: none without a replacement! */
:focus-visible {
  outline: 2px solid #4f46e5;
  outline-offset: 2px;
}

/* Skip link — lets keyboard users bypass navigation */
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  padding: 8px 16px;
  background: #4f46e5;
  color: white;
  z-index: 100;
}
.skip-link:focus {
  top: 0;
}
<!-- Skip link in HTML -->
<a class="skip-link" href="#main-content">
  Skip to main content
</a>

<nav>...long navigation...</nav>

<main id="main-content">
  <!-- Page content -->
</main>

Focus Trapping in Modals

When a modal opens, focus must be trapped inside it — Tab should cycle through the modal's interactive elements, not escape to the page behind. When the modal closes, return focus to the element that triggered it.

// Focus trap for modal dialogs
function trapFocus(modal) {
  const focusable = modal.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const first = focusable[0];
  const last = focusable[focusable.length - 1];

  modal.addEventListener('keydown', (e) => {
    if (e.key !== 'Tab') return;

    if (e.shiftKey && document.activeElement === first) {
      e.preventDefault();
      last.focus();
    } else if (!e.shiftKey && document.activeElement === last) {
      e.preventDefault();
      first.focus();
    }
  });

  first.focus(); // Move focus into modal on open
}

Visual Design and Color Accessibility

Color Contrast Requirements

WCAG AA requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (18px+ bold or 24px+ regular). This isn't arbitrary — it's the threshold where text becomes readable for people with moderate visual impairments.

Element AA Minimum AAA Target Quick Check
Normal text (<18px)4.5:17:1#595959 on white passes
Large text (18px+ bold)3:14.5:1#767676 on white passes
UI components (borders, icons)3:1Buttons, form borders, icons
Focus indicators3:1Must be visible against background

Don't Rely on Color Alone

8% of men are color-blind. Never use color as the only way to convey information. Error states need icons or text, not just red borders. Chart data needs patterns or labels, not just different colors.


<input style="border-color: red;">


<div class="form-group error">
  <label for="email">Email address</label>
  <input id="email" aria-describedby="email-error"
         aria-invalid="true">
  <span id="email-error" class="error-msg">
    ⚠ Please enter a valid email address
  </span>
</div>

Building Accessible Forms

Forms are where accessibility failures hit hardest — they're the gateway to conversions, signups, and transactions. An inaccessible form is a broken funnel.

<form>
  <!-- Always use label + for/id pairing -->
  <div class="field">
    <label for="fullname">Full Name <span aria-hidden="true">*</span></label>
    <input id="fullname" type="text" required
           autocomplete="name"
           aria-required="true">
  </div>

  <!-- Error messages linked via aria-describedby -->
  <div class="field">
    <label for="phone">Phone Number</label>
    <input id="phone" type="tel"
           autocomplete="tel"
           aria-describedby="phone-hint"
           pattern="[0-9]{10}">
    <span id="phone-hint" class="hint">
      10-digit number, no spaces or dashes
    </span>
  </div>

  <!-- Group related fields with fieldset/legend -->
  <fieldset>
    <legend>Preferred contact method</legend>
    <label>
      <input type="radio" name="contact" value="email"> Email
    </label>
    <label>
      <input type="radio" name="contact" value="phone"> Phone
    </label>
  </fieldset>

  <button type="submit">Send Message</button>
</form>

Key form accessibility rules:

  • Every input must have a visible <label> (not just placeholder text)
  • Use autocomplete attributes — they help password managers and assistive tech
  • Link error messages to inputs via aria-describedby
  • Group related inputs with <fieldset> and <legend>
  • Don't remove focus styles — style :focus-visible instead

Testing Tools and Workflow

Automated tools catch about 30-40% of accessibility issues. The rest requires manual testing. Here's the workflow we use at Pillai Infotech:

Automated Testing (CI Pipeline)

Tool Type Best For
axe-coreLibrary (Playwright/Cypress)CI integration, most rules
LighthouseChrome DevTools / CIQuick audits, scoring
WAVEBrowser extensionVisual issue highlighting
eslint-plugin-jsx-a11yESLint pluginCatching issues at write-time (React)
Pa11yCLI / CI runnerAutomated page-level testing

Manual Testing Checklist

  • Keyboard-only navigation — unplug your mouse, use only Tab/Enter/Escape/Arrow keys
  • Screen reader testing — VoiceOver (Mac), NVDA (Windows, free), or JAWS
  • Zoom to 200% — content must remain usable and not overlap
  • Color contrast check — use the browser DevTools contrast checker
  • Reduced motion — test with prefers-reduced-motion: reduce enabled
/* Respect user's motion preferences */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* axe-core integration with Playwright */
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

test('homepage has no accessibility violations', async ({ page }) => {
  await page.goto('/');
  const results = await new AxeBuilder({ page }).analyze();
  expect(results.violations).toEqual([]);
});

Common Accessibility Mistakes We See

After auditing dozens of client sites, these are the issues we find most often:

  1. Missing alt text on images. Every <img> needs an alt attribute. Decorative images get alt="" (empty, not missing). Informative images get descriptive alt text.
  2. Links that say "Click here" or "Read more." Screen readers often list all links on a page — "Click here" repeated 15 times is useless. Use descriptive link text: "Read our TypeScript best practices guide."
  3. No skip navigation link. Keyboard users shouldn't have to Tab through 50 nav links to reach content on every page.
  4. Auto-playing media. Video or audio that plays automatically disorients screen reader users and violates WCAG 1.4.2. Always require user interaction to play.
  5. Removing focus outlines without replacement. outline: none on everything makes your site unusable for keyboard navigators. Use :focus-visible to show outlines only during keyboard navigation.
  6. Form inputs without labels. Placeholder text disappears when typing and isn't reliably read by screen readers. Always use visible <label> elements.
  7. Inaccessible custom dropdowns. Custom select menus built with divs almost always break keyboard navigation and screen reader support. Use <select> or a library like Headless UI that handles ARIA correctly.
Need help building accessible applications? Read our guides on building PWAs, choosing a frontend framework, and web performance optimization. Or explore our web development services where accessibility is part of every project.

Frequently Asked Questions

How much does it cost to make a website accessible?
If built accessible from the start, the cost is near zero — it's just writing better HTML. Retrofitting an existing site typically costs 10-25% of the original development cost, depending on how many custom widgets need rework. The earlier you start, the cheaper it is.
Do accessibility overlays (like accessiBe) work?
No. Accessibility overlays are considered harmful by the disability community and accessibility professionals. They don't fix underlying code issues, often make screen reader experience worse, and provide a false sense of compliance. Several overlay users have been sued despite using the product. Fix the code instead.
Is WCAG 2.2 legally required?
In the US, the ADA has been interpreted to cover websites (no specific WCAG version mandated, but AA is the standard courts reference). The EU's European Accessibility Act requires WCAG 2.1 AA compliance. Canada, UK, Australia, and India also have web accessibility requirements. Even without legal mandate, AA compliance is the industry standard.
Does accessibility hurt design?
The opposite. Accessibility constraints (sufficient contrast, clear labels, consistent navigation) push toward cleaner, more usable design. Apple, Google, and Microsoft all ship beautifully designed products that are highly accessible. Good design and accessibility aren't at odds — they reinforce each other.
How do I convince my team to prioritize accessibility?
Lead with legal risk (lawsuits are expensive), follow with business opportunity (15% of the population), and close with quality (accessible code is better code). If none of that works, run an axe audit on your production site and count the violations — the numbers usually speak for themselves.
What's the minimum I should do for accessibility right now?
Four things that take under an hour: add alt text to all images, ensure every form input has a visible label, check that all text meets 4.5:1 contrast ratio, and verify you can Tab through your entire page without getting stuck. This won't make you fully compliant but covers the most common failures.
Pillai Infotech Development Team
Web Accessibility & Inclusive Design

We build accessible web applications following WCAG 2.2 AA standards. Every project includes accessibility auditing, keyboard navigation testing, and screen reader validation. Explore our web development services.