Skip to content

Accessibility

Web accessibility is about making websites usable by as many people as possible, regardless of their abilities or disabilities. This includes people with visual, auditory, motor, or cognitive impairments.

  • All content and functionality must be perceivable, operable, understandable, and robust.
  • Elements hidden visually using CSS must not be accessible to screen readers or keyboard navigation.
  • Use semantic HTML whenever possible before relying on ARIA attributes.
  • Semantic structure is not only about heading hierarchy.
  • Pages must use the appropriate structural elements whenever possible, such as <header>, <main>, <nav>, <section>, <article>, and <footer>.
  • Text content must be placed inside proper text elements such as <p>, <ul>, <ol>, <li>, or headings, instead of generic <div> or <span> elements.
  • Use links when the element navigates to another page or resource.
  • Use buttons when the element performs an action on the current page, such as opening a modal, toggling content, or submitting a form.
  • Every page must contain one single H1 that represents the main topic of the page.
  • Headings must follow a logical hierarchy (H2H3H4, never skipping levels).
  • Headings should never be empty.
  • Font sizes must be at least 16px.
  • Ensure sufficient color contrast between text and background.
  • Avoid long blocks of dense text; prefer clear paragraphs and lists.
  • The interface must allow browser zoom without breaking content or functionality.
  • All interactive elements must be accessible using the keyboard.
  • Keyboard focus must always be visible.
  • Keyboard navigation must follow a logical order that matches the visual and semantic structure of the page.
  • Users should never get “lost” when navigating with the keyboard.
  • Include skip links to allow users to bypass repetitive or blocking content. Skip links are especially useful for skipping elements such as:
    • the main header
    • the main navigation
    • repeated banners
    • embedded content that may interrupt navigation, such as social media iframes

When content changes dynamically, focus must move to the appropriate element.

Examples include:

  • opening modals
  • displaying error messages
  • navigating between interface views

Focus should never remain on an element that is no longer visible or relevant.

Avoid removing focused elements from the DOM without moving focus to a valid destination.

  • Links or buttons without visible text must include a descriptive aria-label.
  • Links that open in a new window or tab must clearly announce this to screen readers. If an element already has an aria-label, append “opens a new window” instead of replacing it.
  • Links that open in a new tab must use rel="noopener noreferrer".
  • Avoid using non-semantic elements such as <div> or <span> as clickable controls.
<a
href="https://external-site.com"
target="_blank"
rel="noopener noreferrer"
aria-label="Terra Blog, opens a new window"
>
Terra Blog
</a>

Clickable elements must be large enough to interact with comfortably.

Recommended minimum target size:

  • 44 x 44 px for buttons, links, and interactive elements
  • Use the semantic <nav> element for navigation.
  • If semantic elements are not possible, use appropriate ARIA roles such as role="navigation".
  • For dropdown menus:
    • use aria-haspopup="true"
    • toggle aria-expanded="true" / aria-expanded="false" based on state
<button
aria-haspopup="true"
aria-expanded="false"
>
Menu
</button>
  • All meaningful images must include descriptive alt text.
    <img src="chart.png" alt="Sales growth chart for Q1 2024" />
  • Decorative images or icons should be hidden from assistive technologies.
    <img src="divider.png" role="presentation" alt="" />
  • Figure elements must either:
    • contain accessible text, or
    • be excluded using role="none"
  • Every form field must have:
    • a <label> element, or
    • an aria-label
  • Required fields must include aria-required="true".
  • Validation errors must be communicated using aria-invalid.
    <label for="email">Email</label>
    <input
    id="email"
    type="email"
    aria-required="true"
    aria-invalid="false"
    />
  • Search inputs must include role="search" for semantic clarity.

Placeholders must not replace labels.

Placeholders disappear when users start typing and may not be announced consistently by assistive technologies.

Always include a visible <label> for form fields whenever possible.

When content updates dynamically without a page reload, the change must be announced to assistive technologies.

Use aria-live regions to notify screen readers of important updates such as:

  • loading states
  • form validation errors
  • search results
  • status messages

Example:

<p aria-live="polite">Loading results...</p>
<p aria-live="assertive">There was an error submitting the form.</p>
  • aria-live="polite" should be used for non-critical updates.
  • aria-live="assertive" should be used for urgent messages that must be announced immediately.
  • Sliders and carousels must be clearly identified as landmarks.
  • Use aria-label to describe their purpose (e.g. carousel, featured articles).
  • Carousels are often problematic for accessibility. Avoid them when possible.
  • Navigation controls (next / previous) must be accessible and labeled.
  • Pagination items must indicate:
    • their function
    • the current slide
<button aria-label="Next slide"></button>
  • Iframes must include a descriptive title or aria-label.
  • If iframe content is irrelevant to screen-reader users, it should be hidden.
<iframe
src="video.html"
title="Product introduction video"
></iframe>

Users who prefer reduced motion should not be forced to view animations.

Respect the prefers-reduced-motion media query when implementing animations.

Example:

@media (prefers-reduced-motion: reduce) {
* {
animation: none;
transition: none;
}
}

This helps prevent motion sickness and improves accessibility for sensitive users.

For JavaScript animations, check the user preference before triggering motion effects.

Example:

const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
if (!prefersReducedMotion) {
startAnimation();
}

This helps prevent motion sickness and improves accessibility for sensitive users.

Reduced motion can be tested either through the operating system settings or directly in browser developer tools.

Most browsers automatically respect the system accessibility preference.

Example (macOS):

System Settings → Accessibility → Display → Reduce motion

Example (Windows):

Settings → Accessibility → Visual effects → Animation effects

You can simulate the reduced motion preference without changing system settings:

  1. Open DevTools
  2. Press Cmd + Shift + P
  3. Search for Rendering
  4. In Emulate CSS media feature, select:
prefers-reduced-motion: reduce

This allows testing how animations behave when reduced motion is enabled.

Accessibility features should be tested using screen readers to ensure content and interactions are correctly announced.

Common screen readers include:

Screen ReaderPlatform
VoiceOvermacOS / iOS
NVDAWindows
JAWSWindows
TalkBackAndroid

VoiceOver is built into macOS and can be enabled from the system accessibility settings.

System Settings → Accessibility → VoiceOver

Shortcut:

Cmd + F5

Once enabled, navigate the page using:

  • Tab to move between interactive elements
  • Control + Option + Arrow keys to move through content

NVDA is a free screen reader commonly used on Windows.

Download:

https://www.nvaccess.org/download/

After installing, use:

  • Tab to navigate interactive elements
  • arrow keys to read content
  • Insert + F7 to open the list of links

When testing with a screen reader, verify that:

  • page headings are announced in the correct hierarchy
  • links and buttons have meaningful labels
  • images have appropriate alt text
  • form fields announce their labels
  • dynamic content (using aria-live) is announced correctly
  • keyboard navigation works without requiring a mouse

Knowledge Check

Test your understanding of this section

Loading questions...