WCAG Failure Examples (FAIL vs PASS)

Below are real, interview-ready “FAIL vs PASS” implementations for each WCAG item using HTML/CSS/JS (only when needed). Each example is small but realistic and easy to explain while coding or reviewing vendor UI.

Use the toggle buttons in each section to switch between FAIL and PASS. These are perfect to explain during interviews for VPAT/ACR review: you can point to what’s missing (labels, keyboard support, name/role/value, announcements) and why it affects independent task completion.

Tip: When explaining, keep it short: Issue → User impact → Fix.

1) WCAG 1.3.1 — Info and Relationships (Labels / Structure) A

Problem: visual labels exist, but the programmatic relationship is missing (screen readers can’t reliably identify the field).

FAIL: no label association
Email (visual text only)

Screen readers may announce “edit text” with no field purpose.

<div>Email</div>
<input type="email" />
PASS: proper label / relationship

Screen readers announce “Email, edit text”.

<label for="email">Email</label>
<input id="email" type="email" autocomplete="email" />
↑ Back to top

2) WCAG 2.1.1 — Keyboard A

Problem: key workflow actions are mouse-only (common in approval grids / drag interactions).

FAIL: clickable div (not focusable)
Try tabbing to “Approve”
Approve Invoice

This element is not keyboard focusable by default.

<div onclick="approve()">Approve Invoice</div>
PASS: real button + keyboard works

<button type="button">Approve Invoice</button>
↑ Back to top

3) WCAG 4.1.2 — Name, Role, Value A

Problem: custom components don’t expose a correct role/state, so screen readers can’t interpret or operate them reliably.

FAIL: “dropdown” has no state
Approval Route
Select route ▾

No role, no aria-expanded, no relationship between control and menu.

<div onclick="openMenu()">Select route</div>
<div class="menu">...</div>
PASS: button exposes state + controls

<button aria-expanded="false" aria-controls="routeMenu">Select route</button>
<div id="routeMenu" role="menu">...</div>
↑ Back to top

4) WCAG 1.4.3 — Contrast (Minimum) AA

Problem: text contrast is too low (common with badge text, secondary labels, disabled states).

FAIL: low-contrast text
Payment Status: Pending Approval (low contrast)
PASS: sufficient contrast
Payment Status: Pending Approval (meets minimum contrast)
↑ Back to top

5) WCAG 2.4.7 — Focus Visible AA

Problem: keyboard focus is not visible (common when CSS removes outlines).

FAIL: outline removed

Try Tab: Focus moves but you can’t see where it is.

Invoices · Approvals ·
/* BAD */
*:focus { outline: none; }
PASS: strong focus indicator

Try Tab: Focus is clearly visible.

Invoices · Approvals ·
/* GOOD */
:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }
↑ Back to top

6) WCAG 1.4.10 — Reflow AA

Problem: content requires horizontal scrolling at high zoom (common with fixed-width dashboards).

FAIL: fixed multi-column layout

In a narrow viewport (or 400% zoom), this layout forces horizontal scrolling.

Invoice #
Vendor
Amount
.wide-grid{
  display:grid;
  grid-template-columns: 220px 220px 220px; /* forces horizontal scroll */
}
PASS: wraps / reflows

Tiles wrap instead of forcing horizontal scrolling.

Invoice #
Vendor
Amount
.reflow-pass{
  display:flex;
  flex-wrap:wrap;
}
.tile{ flex: 1 1 160px; }
↑ Back to top

7) WCAG 2.4.11 — Focus Not Obscured (Minimum) AA

Problem: keyboard focus should not be hidden by sticky headers/footers (common in enterprise dashboards).

FAIL: focus scrolls under sticky header

Tab through links; focus may be obscured near the top.

Dashboard Invoices Payments Approvals Reports
/* Missing scroll margin / offset for focus targets */
PASS: focus remains visible

Tab through links; focus stays visible (scroll-margin-top applied).

Dashboard Invoices Payments Approvals Reports
a:focus { scroll-margin-top: 70px; }
↑ Back to top

8) WCAG 2.5.8 — Target Size (Minimum) AA

Problem: tap/click targets are too small (motor accessibility issue; dense grids and icon-only buttons are common offenders).

FAIL: tiny icon targets
Invoice row actions (too small)
PASS: 24x24+ targets
Invoice row actions (large enough)
↑ Back to top

9) WCAG 3.3.1 — Error Identification A

Problem: errors are shown visually only and not programmatically linked/announced (common in form-heavy workflows).

FAIL: visual-only error (no association)
Invalid email

Screen readers may not know which field has the error.

<div class="error">Invalid email</div> 
PASS: error linked + announced

Error is associated to the input and announced via role="alert".

<input aria-describedby="errorId" aria-invalid="true">
<div id="errorId" role="alert">...</div>
↑ Back to top

10) WCAG 2.2.1 — Timing Adjustable A

Problem: session timeouts occur without giving the user enough time or a way to extend.

FAIL: timeout with no extension
Session expires in 15 seconds.

No warning dialog. No option to extend.

PASS: warning + extend option
Session expires in 15 seconds.

When time is low, user gets an accessible warning dialog with “Extend time”.

↑ Back to top