Blog

POUR Principles in Web Design: Perceivable, Operable, Understandable, Robust

TestParty
TestParty
April 19, 2025

The Web Content Accessibility Guidelines (WCAG) organize all accessibility requirements under four foundational principles: Perceivable, Operable, Understandable, and Robust—collectively known as POUR. These principles provide a framework for understanding accessibility, guiding design decisions, and evaluating digital experiences.

This guide explains each POUR principle, what it requires, and how to implement it effectively in web design and development.


The Foundation of Web Accessibility

Why POUR Matters

POUR isn't arbitrary—each principle addresses fundamental ways people interact with digital content:

Perceivable: Can users sense the content? People need to receive information through at least one sense—sight, hearing, or touch.

Operable: Can users interact with the interface? People need to navigate, click, type, and control all functionality.

Understandable: Can users comprehend the content and interface? People need to understand both information content and how to use the interface.

Robust: Does content work across technologies? People need content that functions reliably with various assistive technologies.

POUR and WCAG Structure

WCAG 2.2 organizes 87 success criteria under these four principles:

| Principle      | Guidelines | Success Criteria |
|----------------|------------|------------------|
| Perceivable    | 4          | 29               |
| Operable       | 5          | 29               |
| Understandable | 3          | 17               |
| Robust         | 1          | 3                |

Each principle contains guidelines, and each guideline contains testable success criteria at Levels A, AA, and AAA.


Perceivable: Making Content Detectable

The Principle

Information and user interface components must be presentable to users in ways they can perceive. This doesn't require perception through any specific sense—content must be available to at least one sense.

What Perceivable Covers

Guideline 1.1: Text Alternatives Provide text alternatives for non-text content.

Guideline 1.2: Time-Based Media Provide alternatives for audio and video content.

Guideline 1.3: Adaptable Create content that can be presented in different ways.

Guideline 1.4: Distinguishable Make content easier to see and hear.

Implementing Perceivable Design

Text alternatives for images:

<!-- Informative image -->
<img src="chart.png" alt="Q4 sales increased 32% compared to Q3">

<!-- Decorative image -->
<img src="decorative-border.png" alt="" role="presentation">

<!-- Functional image (button) -->
<button>
  <img src="search-icon.svg" alt="Search">
</button>

<!-- Complex image with extended description -->
<figure>
  <img src="org-chart.png" alt="Company organizational structure"
       aria-describedby="org-desc">
  <figcaption id="org-desc">
    The CEO reports to the board. Four VPs report to the CEO:
    Engineering, Product, Sales, and Operations...
  </figcaption>
</figure>

Color contrast requirements:

/* WCAG AA requires 4.5:1 for normal text */
.body-text {
  color: #333333;      /* Dark gray */
  background: #ffffff; /* White */
  /* Contrast ratio: 12.6:1 - passes AA and AAA */
}

/* Large text (18pt+) requires 3:1 */
.heading {
  font-size: 24px;
  color: #595959;      /* Medium gray */
  background: #ffffff;
  /* Contrast ratio: 7:1 - passes AA and AAA */
}

/* Non-text elements require 3:1 */
.button {
  border: 2px solid #0066cc;
  /* Border contrast against background: 4.5:1 */
}

Audio alternatives:

<!-- Video with captions -->
<video controls>
  <source src="product-demo.mp4" type="video/mp4">
  <track kind="captions" src="captions.vtt" srclang="en" label="English">
  <track kind="descriptions" src="descriptions.vtt" srclang="en" label="Audio Descriptions">
</video>

<!-- Podcast with transcript -->
<audio controls src="podcast-episode-42.mp3"></audio>
<a href="transcript-ep42.html">Read full transcript</a>

Common Perceivable Failures

  • Images without alt text
  • Videos without captions
  • Color as only indicator of meaning
  • Insufficient color contrast
  • Content only available through hover states
  • Audio without transcripts

Operable: Enabling Interaction

The Principle

User interface components and navigation must be operable. Users must be able to interact with all functionality, regardless of input method.

What Operable Covers

Guideline 2.1: Keyboard Accessible All functionality available from keyboard.

Guideline 2.2: Enough Time Users can control time limits.

Guideline 2.3: Seizures and Physical Reactions No content that causes seizures.

Guideline 2.4: Navigable Help users navigate and find content.

Guideline 2.5: Input Modalities Support various input methods beyond keyboard.

Implementing Operable Design

Full keyboard accessibility:

// Custom interactive component with keyboard support
class CustomDropdown {
  constructor(element) {
    this.dropdown = element;
    this.trigger = element.querySelector('.trigger');
    this.menu = element.querySelector('.menu');
    this.options = element.querySelectorAll('[role="option"]');

    this.trigger.addEventListener('keydown', this.handleTriggerKeys.bind(this));
    this.menu.addEventListener('keydown', this.handleMenuKeys.bind(this));
  }

  handleTriggerKeys(e) {
    switch(e.key) {
      case 'Enter':
      case ' ':
      case 'ArrowDown':
        e.preventDefault();
        this.openMenu();
        break;
      case 'Escape':
        this.closeMenu();
        break;
    }
  }

  handleMenuKeys(e) {
    switch(e.key) {
      case 'ArrowDown':
        e.preventDefault();
        this.focusNext();
        break;
      case 'ArrowUp':
        e.preventDefault();
        this.focusPrevious();
        break;
      case 'Enter':
        this.selectOption();
        break;
      case 'Escape':
        this.closeMenu();
        this.trigger.focus();
        break;
    }
  }
}

Visible focus indicators:

/* Never remove focus without replacement */
:focus-visible {
  outline: 2px solid #0066cc;
  outline-offset: 2px;
}

/* Custom focus styles for specific elements */
.button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px #ffffff, 0 0 0 5px #0066cc;
}

/* Ensure focus is visible against all backgrounds */
.dark-section :focus-visible {
  outline-color: #ffffff;
}

Skip navigation links:

<body>
  <a href="#main" class="skip-link">Skip to main content</a>
  <a href="#nav" class="skip-link">Skip to navigation</a>

  <header>
    <nav id="nav">...</nav>
  </header>

  <main id="main" tabindex="-1">
    <!-- Main content -->
  </main>
</body>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  padding: 8px;
  background: #000;
  color: #fff;
  z-index: 100;
}

.skip-link:focus {
  top: 0;
}

Target size requirements (WCAG 2.2):

/* Minimum 24x24 CSS pixels */
button,
a,
input[type="checkbox"],
input[type="radio"] {
  min-width: 24px;
  min-height: 24px;
}

/* Touch targets should be larger - 44x44 recommended */
.touch-target {
  min-width: 44px;
  min-height: 44px;
  padding: 10px;
}

Common Operable Failures

  • Keyboard traps (focus can't escape)
  • Mouse-only interactions
  • No visible focus indicator
  • Time limits without controls
  • Flashing content over 3 times per second
  • Missing skip links on complex pages

Understandable: Clarity in Design

The Principle

Information and operation of user interface must be understandable. Users must be able to comprehend content and figure out how to use the interface.

What Understandable Covers

Guideline 3.1: Readable Make text content readable and understandable.

Guideline 3.2: Predictable Make pages appear and operate predictably.

Guideline 3.3: Input Assistance Help users avoid and correct mistakes.

Implementing Understandable Design

Language declaration:

<!-- Primary language -->
<html lang="en">

<!-- Language changes within content -->
<p>The French phrase <span lang="fr">je ne sais quoi</span>
   means a quality that cannot be described.</p>

Predictable navigation:

<!-- Consistent navigation across pages -->
<nav aria-label="Main navigation">
  <ul>
    <li><a href="/products">Products</a></li>
    <li><a href="/services">Services</a></li>
    <li><a href="/about">About</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>

<!-- Navigation remains in same order on all pages -->

Form error handling:

<form novalidate>
  <div class="form-group" aria-live="polite">
    <label for="email">Email address (required)</label>
    <input type="email" id="email"
           aria-required="true"
           aria-invalid="true"
           aria-describedby="email-error">
    <p id="email-error" class="error" role="alert">
      Please enter a valid email address (example: name@domain.com)
    </p>
  </div>

  <div class="form-group">
    <label for="password">
      Password (required)
      <span class="hint">Must be at least 8 characters with one number</span>
    </label>
    <input type="password" id="password"
           aria-required="true"
           aria-describedby="password-hint">
    <p id="password-hint" class="hint">
      Strong passwords include uppercase, lowercase, numbers, and symbols.
    </p>
  </div>
</form>

Consistent identification:

<!-- Same functionality labeled consistently across site -->

<!-- On product page -->
<button class="add-to-cart">Add to Cart</button>

<!-- On category page -->
<button class="add-to-cart">Add to Cart</button>

<!-- NOT inconsistent like: "Add to Cart" vs "Buy Now" vs "Purchase"
     for the same action -->

Clear instructions:

<form>
  <p class="form-instructions">
    Fields marked with <span aria-hidden="true">*</span>
    <span class="visually-hidden">asterisk</span> are required.
  </p>

  <label for="phone">
    Phone number *
    <span class="format-hint">Format: (555) 555-5555</span>
  </label>
  <input type="tel" id="phone"
         aria-required="true"
         placeholder="(555) 555-5555"
         pattern="\([0-9]{3}\) [0-9]{3}-[0-9]{4}">
</form>

Common Understandable Failures

  • Missing page language
  • Unexpected context changes on focus
  • Inconsistent navigation between pages
  • Error messages without clear solutions
  • Required fields not clearly identified
  • No confirmation for significant actions

Robust: Technology Compatibility

The Principle

Content must be robust enough to be interpreted reliably by a wide variety of user agents, including assistive technologies. This ensures content works now and remains accessible as technologies evolve.

What Robust Covers

Guideline 4.1: Compatible Maximize compatibility with current and future user agents.

Implementing Robust Design

Valid HTML structure:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Page Title</title>
</head>
<body>
  <!-- Proper nesting -->
  <header>
    <nav>
      <ul>
        <li><a href="/">Home</a></li>
      </ul>
    </nav>
  </header>

  <!-- Unique IDs -->
  <main id="main-content">
    <h1>Unique Page Heading</h1>
  </main>

  <!-- Proper closing tags -->
  <footer>
    <p>Copyright 2024</p>
  </footer>
</body>
</html>

Proper ARIA usage:

<!-- Custom widget with complete ARIA -->
<div role="tablist" aria-label="Product information">
  <button role="tab"
          id="tab-1"
          aria-selected="true"
          aria-controls="panel-1">
    Description
  </button>
  <button role="tab"
          id="tab-2"
          aria-selected="false"
          aria-controls="panel-2"
          tabindex="-1">
    Specifications
  </button>
</div>

<div role="tabpanel"
     id="panel-1"
     aria-labelledby="tab-1">
  Description content...
</div>

<div role="tabpanel"
     id="panel-2"
     aria-labelledby="tab-2"
     hidden>
  Specifications content...
</div>

Status messages:

<!-- Announce dynamic updates -->
<div role="status" aria-live="polite" aria-atomic="true">
  <!-- Updated content announced to screen readers -->
  3 items added to cart
</div>

<!-- Alert for important messages -->
<div role="alert">
  Your session will expire in 5 minutes.
</div>

<!-- Progress updates -->
<div role="progressbar"
     aria-valuenow="75"
     aria-valuemin="0"
     aria-valuemax="100"
     aria-label="Upload progress">
  75% complete
</div>

Name, Role, Value compliance:

<!-- Interactive elements must expose name, role, and value -->

<!-- Native elements handle this automatically -->
<button>Submit Order</button>
<!-- Name: "Submit Order", Role: button -->

<input type="checkbox" id="terms" checked>
<label for="terms">I agree to terms</label>
<!-- Name: "I agree to terms", Role: checkbox, Value: checked -->

<!-- Custom elements need explicit ARIA -->
<div role="checkbox"
     tabindex="0"
     aria-checked="true"
     aria-labelledby="custom-label">
  <span id="custom-label">I agree to terms</span>
</div>

Common Robust Failures

  • Duplicate ID attributes
  • Invalid HTML nesting
  • Missing ARIA states on custom widgets
  • Broken ARIA references (aria-describedby pointing to non-existent ID)
  • Inappropriate ARIA roles

POUR in Practice

Design Phase

Apply POUR during design:

Perceivable:

  • Specify color contrast ratios
  • Plan for text alternatives
  • Design without color as sole indicator

Operable:

  • Design obvious focus states
  • Include keyboard shortcuts in specs
  • Plan touch target sizes

Understandable:

  • Write clear labels and instructions
  • Design consistent patterns
  • Plan error states

Robust:

  • Specify semantic structure
  • Document component behaviors
  • Plan ARIA requirements

Development Phase

Validate POUR during development:

// Automated POUR checks
const pourChecklist = {
  perceivable: [
    'All images have alt attributes',
    'Color contrast meets 4.5:1',
    'Information not conveyed by color alone',
    'Audio has transcripts'
  ],
  operable: [
    'All interactive elements keyboard accessible',
    'Focus visible on all elements',
    'No keyboard traps',
    'Skip links present'
  ],
  understandable: [
    'Page language declared',
    'Form errors clearly described',
    'Consistent navigation',
    'Clear instructions provided'
  ],
  robust: [
    'Valid HTML structure',
    'ARIA used correctly',
    'Status messages announced',
    'Unique IDs throughout'
  ]
};

Testing Phase

Test each POUR principle:

| Principle      | Testing Method                                          |
|----------------|---------------------------------------------------------|
| Perceivable    | Screen reader, color blindness simulators, zoom to 200% |
| Operable       | Keyboard-only navigation, switch device, voice control  |
| Understandable | Plain language check, user testing, consistency review  |
| Robust         | HTML validation, ARIA testing, cross-browser testing    |

Taking Action

POUR principles provide the conceptual framework for all accessibility work. Understanding why each principle exists—and what user needs it addresses—enables better design decisions and more effective implementation. Use POUR as a mental model when building features and evaluating accessibility.

TestParty provides continuous monitoring across all POUR principles, catching issues before they impact users.

Schedule a TestParty demo and get a 14-day compliance implementation plan.


Related Resources

Contact Us

Automate the software work for accessibility compliance, end-to-end.

Empowering businesses with seamless digital accessibility solutions—simple, inclusive, effective.

Book a Demo