WCAG Principles: POUR
Perceivable, Operable, Understandable, Robust — the four WCAG principles with concrete frontend examples, levels, and how to use them in reviews.
- accessibility
- wcag
- pour
- a11y
WCAG (Web Content Accessibility Guidelines) organizes requirements under four principles: Perceivable, Operable, Understandable, Robust — POUR. If you can classify a bug under POUR, you can explain why it matters to users and map it to success criteria instead of hand-waving “a11y.”
Docs: WCAG 2 overview (W3C), WCAG 2.2, How to meet WCAG, MDN Accessibility.
Conformance levels (A, AA, AAA)
| Level | Meaning in practice |
|---|---|
| A | Minimum baseline — without these, many users are blocked |
| AA | Common legal/product target (e.g. many public-sector and enterprise policies) |
| AAA | Highest; excellent where feasible, not always required for every criterion on every page |
Most product teams aim for WCAG 2.x Level AA. POUR is stable across 2.0/2.1/2.2; versions add criteria under the same principles.
P — Perceivable
Information and UI must be presentable in ways users can perceive — not only via a single sense or medium.
Frontend examples:
| Do | Don’t |
|---|---|
| Text alternatives for images that convey meaning | Icon-only status with no name |
| Captions/transcripts for multimedia | Video announcements with no text path |
| Sufficient color contrast for text/UI | Light gray body text on white |
| Don’t rely on color alone for errors | Red outline only, no text/icon |
| Resize text / reflow without loss | Fixed pixels that clip at 200% zoom |
<img src="/chart.png" alt="Revenue up 12% quarter over quarter" />
<!-- Decorative -->
<img src="/swirl.svg" alt="" />
/* Prefer system-aware motion for vestibular safety (also Operable) */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
Related: color contrast, do not rely on color alone, images alt.
O — Operable
Users must be able to operate the interface — keyboard, pointer, time limits, seizures/vestibular safety, navigation aids.
Frontend examples:
| Do | Don’t |
|---|---|
| All functionality via keyboard | Mouse-only drag with no alternative |
| Visible focus | outline: none with no replacement |
| Skip links to main content | 200 tab stops through mega-nav |
| Sensible focus order matching visual order | tabindex chaos / CSS order for reading order |
| Controllable time limits | Session expired with no warning/extension |
| No seizure-inducing flashes | Unchecked large flashing ads |
<a class="skip-link" href="#main">Skip to main content</a>
<!-- … nav … -->
<main id="main">…</main>
:focus-visible {
outline: 2px solid var(--focus);
outline-offset: 2px;
}
Controls that navigate should be links; actions should be buttons — links vs buttons. Modals need focus management — dialog, focus management.
Touch target size and spacing matter for motor disabilities and real phones — see touch-target guidance on this site.
U — Understandable
Information and operation must be understandable — readable language, predictable UI, input assistance.
Frontend examples:
| Do | Don’t |
|---|---|
Page lang attribute |
Missing or wrong lang |
| Clear labels on inputs | Placeholder-only fields |
| Consistent nav across pages | Random link reordering per route |
| Error identification in text | “Invalid” with no field reference |
| Help for complex inputs | Cryptic validation only after full form wipe |
<html lang="en">
…
<label for="card">Card number</label>
<input
id="card"
name="card"
inputmode="numeric"
autocomplete="cc-number"
aria-describedby="card-hint card-err"
/>
<p id="card-hint">16 digits, no spaces required.</p>
Forms are where Understandable fails loudest — forms, labels, and inputs, accessible forms and errors.
Predictable behavior also means components that don’t trap focus unexpectedly and don’t change context on focus alone (classic WCAG gotcha with aggressive onfocus navigation).
R — Robust
Content must be robust enough to be interpreted by a wide range of user agents, including assistive technologies — valid-ish semantics, correct names/roles/states, future-friendly markup.
Frontend examples:
| Do | Don’t |
|---|---|
| Prefer native HTML controls | <div role="button"> without keyboard |
| Accurate ARIA when native isn’t enough | ARIA that lies (aria-expanded never updated) |
| Unique IDs for label associations | Duplicate IDs breaking labels |
| Stable accessible names | Names that change without reason mid-task |
| Test with AT / accessibility tree | Pixel-only QA |
<!-- Robust: native -->
<button type="button" aria-expanded="false" aria-controls="panel">
Filters
</button>
ARIA is a compatibility layer, not a styling API. First rule of ARIA: don’t use ARIA if a native element works. See ARIA roles overview, accessible names.
Using POUR in code review
Instead of “please fix a11y,” write:
Operable: Modal traps focus incorrectly — Tab escapes to background (WCAG 2.x focus order / modal pattern). Use
<dialog showModal()>or return focus on close.
Perceivable: Error state is color-only; add text /
aria-invalid+ message.
Understandable: Submit errors are toast-only; associate with fields via
aria-describedby.
Robust: Custom listbox missing
aria-activedescendantupdates; follow APG.
Mapping to POUR keeps reviews teachable and maps to audit tools and legal language.
Automated checks vs POUR judgment
Axes/Lighthouse catch many Robust/Perceivable issues (contrast, names, invalid ARIA). They miss:
- Logical focus order in complex widgets
- Whether a flow is completable with AT
- Clear error wording
- Motion sickness from custom animations
Use automation as a gate, not a certificate. Manual keyboard + one screen reader pass on critical flows is still required.
POUR and performance / security (adjacent)
- Slow interactions (INP, Core Web Vitals) hurt Operable for everyone, especially motor/cognitive load.
- XSS that injects UI can break names/roles or phishing overlays — Robust/Understandable fail in the wild.
- Layout shift (CLS) can move targets mid-click — Operable/Perceivable pain.
Interview angle
Spell POUR and give one concrete UI failure per letter. Mention AA as the common bar. Prefer native HTML under Robust. Differentiate automated vs manual testing.
One-liner:
“POUR: can users sense it, use it, understand it, and can AT reliably parse it?”
Related on this site
- Forms, labels, and inputs
- Links vs buttons
- dialog element
- Focus management
- Keyboard accessibility checklist
- Core Web Vitals
- Cascade & Specificity — focus styles and specificity fights
Further reading
- W3C WAI: WCAG 2 Overview
- WCAG 2.2 Recommendation
- How to Meet WCAG (Quickref)
- WAI-ARIA Authoring Practices Guide (APG)
- MDN: Accessibility
Related guides
- Accessible Combobox PatternBuild or evaluate comboboxes with APG keyboard behavior, aria-expanded/activedescendant, and filterable listbox pairing.
- Accessible Forms ErrorsLabel inputs, associate errors with fields, announce failures, and avoid placeholder-only forms that break accessibility.
- Accessible Menus PatternAPG menu and menubar keyboard model — arrow navigation, escape to close, aria-expanded, and when a disclosure is enough.
- Accessible Modals PatternsModal dialogs that work: focus trap, Escape, return focus, aria-modal, and why native dialog or APG patterns beat div soup.
- Accessible Names ComputationHow browsers compute accessible names from content, labels, aria-label, and labelledby — and how that powers Testing Library queries.