Development4 min read

Building Accessible Cookie Consent Banners (WCAG 2.1 AA)

Most cookie banners fail basic accessibility requirements. Here's how to build a consent UI that's both legally compliant and accessible to all users.

JO

James Okafor

Frontend Engineer · 18 February 2026

Why Accessibility Matters for Consent Banners

Cookie consent banners are, by definition, shown to every visitor before they can access your site. That makes them the most universally accessed UI element on your site — and the one most likely to exclude users with disabilities if implemented poorly.

Under the UK Equality Act 2010 and equivalent EU legislation, inaccessible web content can constitute unlawful discrimination. Combine that with GDPR's requirement for freely-given consent, and an inaccessible banner could invalidate your consent records entirely.

The WCAG 2.1 AA Checklist for Consent UIs

1. Keyboard Navigation (2.1.1 — Level A)

Every interactive element in your consent banner must be reachable and operable via keyboard alone:

<!-- Bad: click-only dismiss -->
<div onclick="dismissBanner()">✕</div>

<!-- Good: focusable, keyboard-operable -->
<button type="button" onclick="dismissBanner()" aria-label="Close consent banner">
  <span aria-hidden="true">✕</span>
</button>

Tab order must be logical. When the banner appears, focus should move into it. When dismissed, focus should return to the triggering element or a sensible position in the page.

2. Focus Management

When your consent modal opens, trap focus within it:

function trapFocus(element) {
  const focusableElements = element.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const first = focusableElements[0];
  const last = focusableElements[focusableElements.length - 1];

  element.addEventListener('keydown', (e) => {
    if (e.key !== 'Tab') return;
    if (e.shiftKey) {
      if (document.activeElement === first) {
        last.focus();
        e.preventDefault();
      }
    } else {
      if (document.activeElement === last) {
        first.focus();
        e.preventDefault();
      }
    }
  });

  first.focus();
}

3. ARIA Roles and Labels (4.1.2 — Level A)

Your consent dialog must be announced to screen readers:

<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="consent-title"
  aria-describedby="consent-description"
>
  <h2 id="consent-title">Cookie Preferences</h2>
  <p id="consent-description">
    We use cookies to improve your experience. Choose which categories you accept.
  </p>
  <!-- toggles and buttons -->
</div>

4. Colour Contrast (1.4.3 — Level AA)

Text must meet a minimum contrast ratio of 4.5:1 for normal text, 3:1 for large text. Common failures:

  • Grey text on white background for "less important" decline options (dark pattern)
  • Light blue "Accept" button with white text

Use the WebAIM Contrast Checker or axe DevTools to verify.

5. Toggle Switches

Category toggles are common in preference centres. Ensure they're accessible:

<label class="toggle-label">
  <input
    type="checkbox"
    role="switch"
    aria-checked="false"
    id="analytics-toggle"
  />
  <span class="toggle-track" aria-hidden="true"></span>
  <span class="toggle-label-text">Analytics cookies</span>
</label>

Note: role="switch" communicates the on/off nature to screen readers. Always pair with a visible label.

Dark Patterns to Avoid

The ICO and EDPB have both issued guidance on consent dark patterns. Avoid:

  • Asymmetric friction — "Accept All" is a big colourful button, "Reject All" is buried in settings
  • Pre-ticked boxes — categories pre-selected as "on" by default
  • Misleading language — "I agree to a better experience" instead of "Accept marketing cookies"
  • Endless clicks to decline — users should be able to decline in as few clicks as it takes to accept

Testing Your Banner

Tools to test consent UI accessibility:

  1. axe DevTools (browser extension) — automated WCAG scanning
  2. NVDA + Firefox (free screen reader) — test the full keyboard/screen reader flow
  3. VoiceOver + Safari (macOS/iOS) — test Apple's screen reader
  4. Keyboard-only test — unplug your mouse and try to use the banner

DPOKit's Approach

DPOKit's consent banner is built to WCAG 2.1 AA out of the box:

  • Focus is trapped in the modal and restored on close
  • All interactive elements are keyboard-operable
  • ARIA roles, labels, and live regions are correctly applied
  • Reject All is presented with equal visual prominence to Accept All
  • All default colour combinations meet 4.5:1 contrast ratio

Custom CSS is fully supported — but be aware that overriding styles can break accessibility compliance. Test after any theme customisation.

JO

James Okafor

Frontend Engineer

AccessibilityWCAGCookie ConsentFrontend