DEV Community

Marcc Atayde
Marcc Atayde

Posted on

Web Accessibility (WCAG) for Business Websites: A Practical Developer's Checklist

Web Accessibility (WCAG) for Business Websites: A Practical Developer's Checklist

Here's an uncomfortable truth: roughly 15% of the world's population lives with some form of disability. If your business website isn't accessible, you're not just locking out potential customers — you're also exposing your organisation to legal risk, tanking your SEO, and shipping code that's objectively harder to maintain. Yet most development teams treat accessibility as a post-launch checkbox rather than a first-class engineering concern.

This article cuts through the abstract WCAG guidelines and gives you concrete, actionable patterns you can apply today, whether you're building a Laravel-powered monolith, a Livewire SPA, or a headless frontend.


What WCAG Actually Means (Without the Jargon)

The Web Content Accessibility Guidelines (WCAG), published by the W3C, are organised around four core principles — often abbreviated as POUR:

  • Perceivable — information must be presentable in ways users can perceive
  • Operable — UI components must be operable by all users
  • Understandable — content and operation must be understandable
  • Robust — content must be interpreted reliably by assistive technologies

WCAG has three conformance levels: A (minimum), AA (the legal and industry standard most businesses target), and AAA (enhanced). If a client asks for "WCAG compliance," they almost always mean WCAG 2.1 AA.


The Developer's Quick-Win Checklist

1. Semantic HTML First

The single highest-leverage accessibility improvement you can make costs nothing: stop using <div> for everything. Screen readers rely on semantic HTML to understand page structure.

<!-- ❌ Bad -->
<div class="btn" onclick="submitForm()">Submit</div>

<!-- ✅ Good -->
<button type="submit">Submit</button>
Enter fullscreen mode Exit fullscreen mode

Use <nav>, <main>, <article>, <aside>, <header>, and <footer> as landmark regions. They're free, they cost zero bytes of JavaScript, and they immediately improve screen reader navigation.

2. ARIA — Use It Sparingly

ARIA (Accessible Rich Internet Applications) attributes exist to fill gaps where semantic HTML isn't enough — not to replace it. The first rule of ARIA is: don't use ARIA if a native HTML element can do the job.

That said, dynamic UI components like modals, tabs, and dropdowns genuinely need ARIA:

<!-- Modal dialog example -->
<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="modal-title"
  aria-describedby="modal-description"
>
  <h2 id="modal-title">Confirm Deletion</h2>
  <p id="modal-description">This action cannot be undone.</p>
  <button autofocus>Cancel</button>
  <button>Delete</button>
</div>
Enter fullscreen mode Exit fullscreen mode

When role="dialog" is active, autofocus should move keyboard focus inside the modal. When it closes, focus must return to the trigger element. Forgetting this is one of the most common keyboard-trap bugs in SPAs.

3. Colour Contrast — Automate the Check

WCAG 2.1 AA requires:

  • 4.5:1 contrast ratio for normal text
  • 3:1 for large text (18px+ regular or 14px+ bold)
  • 3:1 for UI components and graphical objects

Don't eyeball this. Add axe-core to your test suite:

npm install --save-dev @axe-core/playwright
Enter fullscreen mode Exit fullscreen mode
// playwright.spec.js
import { checkA11y, injectAxe } from 'axe-playwright';

test('homepage has no critical a11y violations', async ({ page }) => {
  await page.goto('http://localhost:8000');
  await injectAxe(page);
  await checkA11y(page, null, {
    includedImpacts: ['critical', 'serious'],
  });
});
Enter fullscreen mode Exit fullscreen mode

This catches contrast failures, missing alt text, unlabelled form fields, and dozens of other issues automatically on every CI run.

4. Keyboard Navigation and Focus Management

Every interactive element must be reachable and operable via keyboard alone. Test this yourself: unplug your mouse and try navigating your site with Tab, Shift+Tab, Enter, and arrow keys.

Never do this:

/* ❌ Destroys keyboard navigation for everyone */
*:focus {
  outline: none;
}
Enter fullscreen mode Exit fullscreen mode

Instead, style focus indicators to match your design system:

/* ✅ Visible, on-brand focus ring */
*:focus-visible {
  outline: 2px solid #2563EB;
  outline-offset: 3px;
  border-radius: 4px;
}
Enter fullscreen mode Exit fullscreen mode

The :focus-visible pseudo-class is key here — it shows the outline only for keyboard navigation, not mouse clicks, so you get accessibility without visual clutter.

5. Forms — The Most Common Failure Point

Forms are where accessibility falls apart most often. Every input needs a programmatically associated label — placeholder is not a substitute.

<!-- ❌ Placeholder-only, inaccessible -->
<input type="email" placeholder="Email address">

<!-- ✅ Properly labelled -->
<div>
  <label for="email">Email address</label>
  <input
    type="email"
    id="email"
    name="email"
    autocomplete="email"
    aria-required="true"
    aria-describedby="email-hint"
  >
  <span id="email-hint" class="text-sm text-gray-500">
    We'll never share your email.
  </span>
</div>
Enter fullscreen mode Exit fullscreen mode

For inline validation errors, associate the error message with the field using aria-describedby and set aria-invalid="true" on the input when validation fails.

6. Images and Alt Text — Context Matters

The rule is simple but often misapplied:

  • Informative images → descriptive alt text
  • Decorative imagesalt="" (empty string, not omitted)
  • Functional images (e.g., logo linking to homepage) → describe the function: alt="HanzWeb homepage"
<!-- Decorative divider image -->
<img src="/divider.svg" alt="">

<!-- Chart conveying data -->
<img
  src="/q3-revenue-chart.png"
  alt="Bar chart showing Q3 revenue up 23% year-over-year"
>
Enter fullscreen mode Exit fullscreen mode

Testing Beyond Automated Tools

Automated scanners like axe-core catch roughly 30–40% of accessibility issues. The rest require manual testing:

  1. Screen reader testing — Use NVDA (Windows, free) or VoiceOver (macOS/iOS, built-in) to navigate your critical user journeys
  2. Zoom testing — Set browser zoom to 200% and verify content doesn't break or overlap (WCAG 1.4.4)
  3. Reduced motion — Respect prefers-reduced-motion for users with vestibular disorders
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
Enter fullscreen mode Exit fullscreen mode

Accessibility in the Laravel / TALL Stack Context

If you're building with Livewire, pay extra attention to dynamic content updates. When Livewire re-renders a component, focus can silently reset to the document body, which is disorienting for keyboard and screen reader users.

Use wire:ignore on elements that shouldn't be re-rendered, and dispatch focus-management events where needed. The team at https://hanzweb.ae integrates accessibility audits directly into the Livewire component development workflow, which surfaces these focus-trap issues during build rather than after launch.

For Alpine.js components, the Alpine Accessibility plugin provides trap and focus utilities that handle modal and dropdown patterns correctly out of the box.


Conclusion

Accessibility isn't a niche concern or a legal box to tick — it's a measure of how well you actually built something. The patterns above — semantic HTML, proper ARIA usage, colour contrast checks in CI, keyboard-navigable focus management, and correctly labelled forms — represent the 20% of effort that solves 80% of real-world WCAG failures.

Start by adding axe-core to your test pipeline this week. Run it against your three most-visited pages. Fix what it surfaces. Then do a keyboard-only walkthrough of your primary conversion flow. You'll be surprised how much you find — and how straightforward most of it is to fix.

Top comments (0)