Skip to content
C Codeloom
Web

Web Accessibility WCAG Essentials Every Dev Should Know

A practical guide to the WCAG fundamentals: semantic HTML, keyboard support, contrast, focus management, and ARIA used responsibly.

·5 min read · By Yash Kesharwani
Intermediate 9 min read

What you'll learn

  • The four WCAG principles and what they mean in code
  • How semantic HTML solves most accessibility problems
  • How to build keyboard-friendly interactions
  • How to use ARIA only when needed
  • How to test accessibility without specialized hardware

Prerequisites

  • Basic HTML knowledge

Accessibility is not a separate feature. It is a property of the same HTML and CSS you already write. WCAG, the Web Content Accessibility Guidelines, gives you a checklist, but the day-to-day work is mostly about using the right element, exposing state correctly, and making sure the keyboard can reach everything.

The four principles

WCAG groups requirements under POUR:

  • Perceivable: users can perceive the content. Text alternatives, captions, contrast.
  • Operable: users can operate the interface. Keyboard, time, motion.
  • Understandable: users can understand the content. Language, predictability, error help.
  • Robust: tools can interpret the content. Valid HTML, correct roles.

Most teams aim for WCAG 2.1 or 2.2 at level AA. AAA is stricter and often unrealistic across a whole site.

Semantic HTML does the heavy lifting

The single most effective thing you can do is use the right element. A button is a button. A link goes somewhere. A heading describes a section.

<!-- bad -->
<div class="btn" onclick="save()">Save</div>

<!-- good -->
<button type="button" onclick="save()">Save</button>

The bad version is not focusable, not announced as a button, and not activated by Enter or Space. The good version gets all of that for free.

Use:

  • button for actions on the same page.
  • a href for navigation.
  • h1 through h6 for outline, not for font size.
  • label for every form control.
  • nav, main, header, footer for landmarks.

Labels and names

Every interactive element needs an accessible name. For inputs, prefer a real label:

<label for="email">Email</label>
<input id="email" type="email" name="email">

If you cannot show a visible label, use aria-label or aria-labelledby:

<button aria-label="Close dialog">
  <svg aria-hidden="true">...</svg>
</button>

Decorative icons should have aria-hidden="true" so they are not announced.

Images need an alt attribute. Use empty alt="" for decorative images. Write alt text that describes the meaning, not the pixels.

Keyboard support

If a user cannot reach or operate your interface with a keyboard, it fails. Two non-negotiables:

  • Tab and Shift+Tab move through interactive elements in a sensible order.
  • Enter or Space activates the focused control.

Common traps:

  • Custom widgets that swallow focus. Always provide a way out with Tab or Escape.
  • Modals that allow background focus. Trap focus inside the dialog while it is open and restore it to the trigger on close.
  • Click handlers on non-interactive elements. Either switch to button or add role="button", tabindex="0", and a key handler. Switching the element is almost always better.

Test by unplugging the mouse. If you cannot complete the task, real users cannot either.

Focus visibility

Never remove the focus outline without replacing it. Many designs hide :focus because the default outline is ugly with a mouse. Use :focus-visible instead:

button:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}

This shows the outline for keyboard focus and hides it for mouse users.

Color and contrast

WCAG AA requires:

  • 4.5:1 contrast for normal text.
  • 3:1 for large text (about 24px regular or 18px bold).
  • 3:1 for graphical UI like form borders and focus indicators.

Color must not be the only signal. A red error message also needs an icon or text. Form validation should not rely on border color alone.

Tools: Chrome DevTools shows contrast in the color picker. axe and Lighthouse audit pages in seconds.

ARIA: the rule of least power

ARIA lets you describe roles and states that HTML cannot express on its own. The first rule of ARIA is to avoid it when a native element does the job.

When you do need it, follow the patterns in the WAI ARIA Authoring Practices. A few common ones:

<button aria-expanded="false" aria-controls="menu-1">Menu</button>
<ul id="menu-1" hidden>...</ul>
<div role="alert">Failed to save. Try again.</div>
<div role="dialog" aria-modal="true" aria-labelledby="title">
  <h2 id="title">Confirm delete</h2>
  ...
</div>

Three rules:

  • Do not change role lightly. Screen readers depend on consistency.
  • Keep aria- state attributes in sync with reality. A stale aria-expanded is worse than none.
  • Do not add tabindex greater than 0. It scrambles tab order across the page.

Forms that help users recover

  • Associate every input with a label.
  • Mark required fields visually and with aria-required="true".
  • Show errors near the field, not just at the top. Link to them with aria-describedby.
  • Do not validate on every keystroke. Validate on blur or submit, then announce errors politely.
<label for="email">Email</label>
<input id="email" type="email" aria-describedby="email-err" aria-invalid="true">
<p id="email-err">Enter a valid email address.</p>

Motion, time, and media

  • Respect prefers-reduced-motion. Cut or shorten non-essential animations.
  • Avoid auto-playing media with sound.
  • Provide captions for video, transcripts for audio.
  • Give users enough time. If a session expires, warn them and let them extend.

Testing without specialized hardware

You will not catch everything without testing on a real screen reader, but you can catch a lot with a short loop:

  1. Tab through the page. Can you reach and use every control?
  2. Zoom to 200 percent. Does anything overflow or disappear?
  3. Run axe DevTools or Lighthouse. Triage the issues.
  4. Turn on VoiceOver on macOS or NVDA on Windows. Navigate the page by headings and landmarks.
  5. Try the page with prefers-reduced-motion and a forced color scheme.

Add an automated accessibility check to your test suite. Tools like @axe-core/playwright catch regressions before they ship.

Wrap up

Accessibility work concentrates in a small number of habits: use real elements, label everything, keep focus visible, write text that survives without color, and add ARIA only when HTML cannot express the meaning. Most of WCAG falls out of those habits. The rest is cleanup.