Back to blog
Accessibility

WCAG Accessibility Basics Every Developer Should Know

wcaga11yweb-development

When I first started thinking seriously about web accessibility, I made a mistake that I think many developers make: I treated it as a checklist to satisfy rather than a practice to embrace. I would run an automated scanner, fix the red items, and call it done. It took building an actual accessibility tool — A11yMate — for me to understand how much I was missing and how much it mattered.

Accessibility is not a feature you bolt on at the end. It is a quality of your software that affects real people in real ways. Roughly 15% of the world's population lives with some form of disability. That is over a billion people. When your website is inaccessible, you are not failing an audit — you are excluding human beings.

This post covers the fundamentals of WCAG (Web Content Accessibility Guidelines) that every developer should understand, with practical examples you can apply today.

What Is WCAG?

WCAG stands for Web Content Accessibility Guidelines. It is a set of recommendations published by the World Wide Web Consortium (W3C) through the Web Accessibility Initiative (WAI). The current version that most organizations reference is WCAG 2.2, released in October 2023.

WCAG defines three levels of conformance:

  • Level A: The minimum. If you do not meet these, your site has serious accessibility barriers.
  • Level AA: The standard target for most organizations. This is what laws like the ADA and the European Accessibility Act typically reference.
  • Level AAA: The highest standard. Difficult to achieve across an entire site but worth pursuing for critical content.

Most developers should aim for Level AA conformance. It covers the vast majority of accessibility needs without requiring impractical constraints.

The Four Principles: POUR

WCAG is organized around four principles, commonly known by the acronym POUR. Every guideline and success criterion falls under one of these.

1. Perceivable

Users must be able to perceive the content. If someone cannot see, they need the content presented in another way. If someone cannot hear, they need alternatives to audio.

What this means in practice:

  • Every image needs an alt attribute. Not just any alt text — meaningful alt text that conveys the purpose of the image. A decorative image should have alt="" (empty) so screen readers skip it. An informative image should describe what it communicates.
  • Videos need captions. Not auto-generated captions that say "unintelligible" every third sentence — actual accurate captions.
  • Color must not be the only way to convey information. If your form shows errors only by turning the field border red, colorblind users will miss it. Add text, icons, or patterns alongside color.

2. Operable

Users must be able to operate the interface. Not everyone uses a mouse. Some people navigate entirely with a keyboard. Others use switch devices, voice commands, or eye-tracking technology.

What this means in practice:

  • Every interactive element must be reachable and usable with a keyboard alone.
  • Focus indicators must be visible. That blue outline browsers add to focused elements? Stop removing it with outline: none unless you are replacing it with something equally visible.
  • Users must have enough time to read and use content. Auto-rotating carousels, session timeouts without warnings, and disappearing notifications are all problematic.

3. Understandable

Users must be able to understand the content and how the interface works. This covers both the readability of text and the predictability of UI behavior.

What this means in practice:

  • The page language must be declared with the lang attribute on the <html> element. Screen readers use this to switch pronunciation.
  • Form inputs need visible labels. Placeholder text is not a label — it disappears when you start typing.
  • Error messages must be specific and helpful. "Invalid input" is useless. "Please enter a valid email address (example: name@domain.com)" is helpful.

4. Robust

Content must be robust enough to be interpreted by a variety of user agents, including assistive technologies. This is about writing clean, standards-compliant code.

What this means in practice:

  • Use semantic HTML. A <button> is not the same as a <div onclick="..."> even if they look identical. The button communicates its role to assistive technology automatically.
  • Close your tags. Fix your validation errors. Use valid ARIA attributes.
  • Test with multiple browsers and screen readers, not just your default setup.

The Most Common Violations

After building an accessibility checker and scanning thousands of websites, I have seen the same problems repeatedly. Here are the top offenders:

Missing Alt Text on Images

This is the single most common violation on the web. It is also the easiest to fix.

<!-- Bad -->
<img src="chart-q4-revenue.png">

<!-- Good: informative image -->
<img src="chart-q4-revenue.png" alt="Q4 revenue chart showing 23% growth from Q3">

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

The rule is simple: if the image conveys information, describe that information. If it is purely decorative, mark it as such with an empty alt attribute.

Insufficient Color Contrast

WCAG Level AA requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (18pt or 14pt bold). You would be surprised how many popular websites fail this.

Light gray text on a white background might look elegant in a design mockup, but it is unreadable for many people. Use a contrast checker — there are dozens of free ones online — and verify your color combinations.

/* Bad: ratio of about 2.5:1 */
color: #999999;
background-color: #ffffff;

/* Good: ratio of about 7:1 */
color: #595959;
background-color: #ffffff;

Missing Form Labels

Every form input needs a programmatically associated label. This means using the <label> element with a matching for attribute, or wrapping the input inside the label.

<!-- Bad: no label association -->
<span>Email</span>
<input type="email" id="email">

<!-- Good: explicit label -->
<label for="email">Email</label>
<input type="email" id="email">

<!-- Also good: implicit label -->
<label>
  Email
  <input type="email">
</label>

Screen readers announce the label when a user focuses on the input. Without this association, the user hears "edit text" with no context about what they should enter.

Missing Document Language

This one takes five seconds to fix and affects every screen reader user on your site:

<!-- Bad -->
<html>

<!-- Good -->
<html lang="en">

Without the lang attribute, screen readers have to guess the language, and they often guess wrong. This results in English content being read with a French or German pronunciation engine, which is incomprehensible.

Keyboard Traps

A keyboard trap occurs when a user can tab into an element but cannot tab out. Modal dialogs are the most common culprit. When a modal opens, focus should move into the modal. When it closes, focus should return to the element that opened it. And the user should be able to close the modal by pressing Escape.

// Essential modal keyboard handling
dialog.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') {
    closeModal();
    triggerButton.focus(); // Return focus to the trigger
  }

  // Trap focus within the modal
  if (e.key === 'Tab') {
    const focusable = dialog.querySelectorAll(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    );
    const first = focusable[0];
    const last = focusable[focusable.length - 1];

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

Keyboard Navigation Done Right

Keyboard accessibility is one of those areas that seems simple but has many subtleties. Here are the essentials:

Use native HTML elements whenever possible. Buttons, links, form controls — they all come with keyboard support built in. The moment you start building custom interactive widgets from <div> and <span> elements, you take on the responsibility of reimplementing all that behavior.

Maintain a logical tab order. The tab order should follow the visual layout of the page. Do not use positive tabindex values (tabindex="5") to rearrange the order — it creates confusion. Use tabindex="0" to add elements to the natural tab order and tabindex="-1" to make elements focusable programmatically but not via Tab.

Provide visible focus indicators. When a user presses Tab, they need to see where focus is. The default browser focus ring works fine. If your design requires a custom focus style, make it at least as visible:

/* Custom focus style that's visible on any background */
:focus-visible {
  outline: 3px solid #4A90D9;
  outline-offset: 2px;
}

Support expected keyboard patterns. Arrow keys for navigating within components (tabs, menus, radio groups). Enter and Space for activation. Escape for dismissal.

ARIA: Use Sparingly and Correctly

ARIA (Accessible Rich Internet Applications) attributes let you communicate roles, states, and properties to assistive technology. They are powerful and frequently misused.

The first rule of ARIA is: do not use ARIA if you can use native HTML instead. A <button> is always better than <div role="button">. Native elements handle keyboard events, focus management, and screen reader announcements automatically.

When you do need ARIA, here are the most commonly useful attributes:

<!-- aria-label: provides an accessible name when visible text is insufficient -->
<button aria-label="Close dialog">X</button>

<!-- aria-describedby: links to a description -->
<input type="password" aria-describedby="password-hint">
<p id="password-hint">Must be at least 8 characters with one number.</p>

<!-- aria-live: announces dynamic content changes -->
<div aria-live="polite">3 search results found</div>

<!-- aria-expanded: communicates toggle state -->
<button aria-expanded="false" aria-controls="menu">Menu</button>
<ul id="menu" hidden>...</ul>

<!-- aria-hidden: hides decorative content from screen readers -->
<span aria-hidden="true">★</span> 4.5 out of 5 stars

A critical warning: incorrect ARIA is worse than no ARIA. Adding role="button" to a div without also handling keyboard events and focus management actively misleads assistive technology users. They are told it is a button, they try to press Enter, and nothing happens.

Testing Your Accessibility

Automated tools catch about 30-40% of accessibility issues. The rest require manual testing. Here is a practical testing approach:

Step 1: Run automated scans. Tools like axe, Lighthouse, or WAVE will catch the low-hanging fruit — missing alt text, contrast issues, missing labels, invalid ARIA.

Step 2: Keyboard test. Put your mouse in a drawer. Navigate your entire site using only Tab, Shift+Tab, Enter, Space, Escape, and arrow keys. Can you reach everything? Can you use everything? Can you see where focus is at all times?

Step 3: Screen reader test. This is uncomfortable at first but essential. On macOS, use VoiceOver (built in, activated with Cmd+F5). On Windows, use NVDA (free download). Navigate your site and listen. Does it make sense? Can you find the information you need?

Step 4: Zoom test. Zoom your browser to 200%. Does the layout still work? Is any content cut off or overlapping? WCAG requires usability up to 200% zoom.

Step 5: Reduced motion test. Enable "Reduce Motion" in your operating system's accessibility settings. Do your animations respect this preference?

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

Start Today, Not Tomorrow

Accessibility can feel overwhelming when you look at the full WCAG specification. It is over 80 success criteria across four principles and three conformance levels. But you do not need to tackle everything at once.

Start with these five actions on your current project:

  1. Add the lang attribute to your <html> element.
  2. Check that every image has an appropriate alt attribute.
  3. Verify that every form input has a visible, associated label.
  4. Test your color contrast ratios with a free tool.
  5. Navigate your site with only the keyboard and fix whatever breaks.

These five steps alone will address a significant percentage of the accessibility barriers on most websites. From there, you can work through the WCAG guidelines systematically, adding improvements with each release.

Accessibility is not a destination. It is a practice. The web was designed to be for everyone. Every line of code you write is an opportunity to make that vision real.

WCAG Accessibility Basics Every Developer Should Know