Guides

    WCAG 2.2 AA for Players, Not Just Captions

    A player audit sheet for WCAG 2.2 AA: keyboard, pause/stop/hide, audio control, chrome contrast, and captions that work in the embed.

    Versely Team8 min read

    A caption file sitting next to an MP4 does not make the page accessible. WCAG 2.2 Level AA is a claim about the chrome, the keys, whether autoplay can be stopped, and whether captions appear in the embed the visitor uses. Teams keep failing audits on the player after they already captioned the asset.

    A laptop on a desk showing a video editing timeline and playback controls

    What AA actually asks of a player

    Level AA includes every Level A criterion plus every AA criterion. For a prerecorded landing-page video, people remember 1.2.2 Captions (Prerecorded) (A) and 1.2.5 Audio Description (Prerecorded) (AA). The player criteria they skip are the ones that fail the page even when the file is fine.

    Success criterion Level What it means on a player
    2.1.1 Keyboard A Play, pause, seek, mute, volume, captions, fullscreen work without a mouse.
    2.4.7 Focus Visible AA The focused control has a visible indicator.
    2.4.11 Focus Not Obscured (Minimum) AA Overlays (cookie banners, sticky CTAs) do not fully hide the focused control. New in 2.2.
    2.5.7 Dragging Movements AA Seek and volume cannot be drag-only; click, tap, or a key must set the value. New in 2.2.
    2.5.8 Target Size (Minimum) AA Targets are 24 by 24 CSS pixels, or spaced so a 24px circle around an undersized target hits nothing else. New in 2.2.
    1.4.11 Non-text Contrast AA Chrome needed to identify a control or its state contrasts at least 3:1 against adjacent color.
    1.4.2 Audio Control A Autoplay audio over 3 seconds can be paused, stopped, or volume-controlled independently of system volume.
    2.2.2 Pause, Stop, Hide A Auto-started motion lasting over 5 seconds, next to other content, can be paused, stopped, or hidden.
    1.2.2 Captions (Prerecorded) A Captions exist and the player can present them.
    4.1.2 Name, Role, Value A Assistive tech can read each control's name, role, and state.

    Native controls on an unmodified <video> are exempt from some of these (1.4.11 and 2.5.8 carve out user-agent chrome the author did not restyle). Skin a custom player and the exemptions drop. The pretty marketing player is usually the failure, not the default one.

    Keyboard, pause, and audio: the three traps that caption files never catch

    Keyboard. Tab to the player, see focus, play/pause with Space or Enter. Arrows or equivalent must move the playhead and volume without a drag. Focus lost in a canvas, or seek-by-drag-only, fails 2.1.1 and 2.5.7. Click or tap on the slider track, or discrete buttons, is the alternative. Dragging can stay; it cannot be the only method.

    Pause, Stop, Hide. A hero loop next to a headline is 2.2.2: motion that starts on its own, lasts more than five seconds, and runs beside other content. Pause or stop on the player, a page-level pause control, or a poster until the user hits play all work. A silent decorative loop with no stop still fails.

    Audio Control. Autoplay sound over three seconds needs pause, stop, or volume independent of the OS. Muting the laptop is not that mechanism. Autoplay can block a screen-reader user from finding the control that would stop it. The reliable pattern is no autoplay audio. If marketing wants sound-on, put mute first in the tab order.

    None of this is fixed by attaching a .vtt in the DAM. It is page behavior.

    Contrast of chrome, not just of captions

    Caption contrast is a separate job (text over moving picture; see reading speed, line breaks, and contrast). Player chrome is 1.4.11 Non-text Contrast: 3:1 against adjacent color for whatever identifies the control and its state.

    Light-grey play icons on a washed-out poster fail. A 1px light-blue focus ring on white fails 2.4.7 with 1.4.11. Sample the pixels, not the hex in Figma. If chrome sits on video, sample the lightest and darkest frames, or put it on a measurable scrim.

    Type contrast for generated graphics uses 4.5:1 (or 3:1 for large-scale text) under 1.4.3. Do not mix the numbers: labels are text; the play triangle is not.

    A 16-pixel mute next to a 16-pixel captions toggle with no gap fails 2.5.8. Enlarge the hit area (padding counts) or space the 24px circles apart.

    Captions that work in the embed

    WCAG's definition of captions covers speech and non-speech needed to understand the content: sound effects, music, laughter, speaker identification, location. A speech-only auto-transcript is useful for muted feeds and still incomplete as captions.

    Closed captions can be turned off. Open captions cannot; burned-in captions are open. Both can meet 1.2.2 if they are complete and synchronized. They fail the page if the visitor never sees them.

    1. What did you ship to the player? A sidecar .vtt with kind="captions" (not kind="subtitles"), or pixels in the file? Sidecars restyle and index; burn-in survives a player with no track support. Burned-in versus SRT/VTT is the destination split.
    2. Does this embed load that track? Many wrappers never pass a <track>. Iframe hosts only show captions you uploaded, with the button left on. A VTT the component ignores is not a caption.
    3. Can a keyboard user toggle them? Name, role, state, visible focus, 24px target.
    4. Are they still captions once styled? Dropping speaker IDs or non-speech is not 1.2.2 just because glyphs appeared.

    For muted feeds, burn-in is what shows up. For a site embed, ship a sidecar and confirm the player renders it. Versely's caption tools composite styled, transcribed captions into frames. For a sidecar, start from a plain transcript and author the VTT the embed loads. Add captions for the burn-in pass; caption style presets control outline and plate. They do not fix a player that never loads a track.

    The player audit sheet

    Run this on the live URL, not a staging page that still used native controls. Keyboard first, then mouse, then captions on.

    Before play

    1. Tab to the player. Is a control focused, and is that focus visible against the poster?
    2. Is anything autoplaying? If motion lasts more than 5 seconds next to other content, is there pause/stop/hide?
    3. If audio autoplays more than 3 seconds, is pause/stop or independent volume in the tab order near the top of the page?
    4. Does a cookie banner, sticky header, or chat launcher fully cover the focused control? (2.4.11)

    Controls

    1. Play, pause, mute, captions, seek, fullscreen: each operable from the keyboard.
    2. Seek and volume: click/tap or keys change the value without dragging.
    3. Each control is at least 24×24 CSS pixels or has 2.5.8 spacing.
    4. Icons and states (playing, muted, captions on) meet 3:1 against adjacent color.
    5. A screen reader announces name, role, and state for each control.

    Captions in this embed

    1. Turn captions on from the player. Do they appear?
    2. Do they include speaker changes and meaningful non-speech, not only words?
    3. Do they stay synchronized for the full runtime, not just the first line?
    4. Do they remain readable over the brightest and busiest frames (plate or outline, not color alone)?

    Page, not player

    1. If the video carries information not in the surrounding text, is audio description available (1.2.5), or is every meaningful visual already spoken?
    2. Can someone who never uses the player still get the offer from the heading, body, and transcript?

    Log pass/fail per row with a screenshot of the failing control. The caption file is one row. The rest is why caption-only jobs bounce. For a library under the European Accessibility Act, this is the per-page check a bulk caption pass does not replace.

    FAQ

    Does a YouTube or Vimeo iframe pass WCAG 2.2 AA because those players have captions?

    No. You still have to provide captions the host will serve, leave the control enabled, and meet autoplay, pause, and overlay rules on the page around the iframe. A custom overlay that intercepts keys puts you back in author-controlled territory.

    We burned captions into the file. Do we still need a captions button?

    Open captions satisfy 1.2.2 if they are complete and synchronized. You do not need a toggle for a track that cannot be turned off. You still need keyboard, pause/stop/hide, audio control, contrast, and target size on the remaining chrome.

    Native <video controls> looked fine. Our designed player failed. Why?

    Because 1.4.11 and 2.5.8 exempt unmodified user-agent controls and apply once you replace them. Custom play buttons, 14-pixel icon rows, and drag-only scrubbers are in scope. Keep native controls or build the custom bar to the table above.

    Is audio description a player problem or a file problem?

    Both. 1.2.5 is about the described audio existing. The player still has to expose it, as a second cut or a selectable track, the way it exposes captions. A described WAV that never ships in the embed is the AD version of a VTT the component never loads.