# Voluntary Product Accessibility Template (VPAT)

**Date: March 30, 2026** (updated with external audit findings)

## VPAT 2.4 Rev — WCAG 2.1 Edition

### Product Information

| Field                   | Value                                                                                                                                                              |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Product Name**        | Remotion Pro                                                                                                                                                       |
| **Product Version**     | Branch `master`                                                                                                                                                    |
| **Report Date**         | 2026-03-30                                                                                                                                                         |
| **Contact**             | [remotion.dev/contact](https://remotion.dev/contact)                                                                                                               |
| **Evaluation Methods**  | External audit (Windows, Chrome + NVDA) by Victoria; live browser audit, accessibility tree inspection, source code review, Axe DevTools, Colour Contrast Analyser |
| **Applicable Standard** | WCAG 2.1 Level AA                                                                                                                                                  |

### Pages Audited

#### Public Pages

| Page           | URL                         | Title                                       |
| -------------- | --------------------------- | ------------------------------------------- |
| Homepage       | `/`                         | Remotion Pro                                |
| Login          | `/login`                    | Login \| Remotion Pro                       |
| Store          | `/store`                    | Store \| Remotion Pro                       |
| Store Product  | `/store/[product]`          | [Product name] \| Remotion Pro              |
| Store Interest | `/store/[product]/interest` | (varies)                                    |
| License        | `/license`                  | Licensing \| Remotion Pro                   |
| FAQ            | `/faq`                      | FAQ \| Remotion Pro                         |
| Contact        | `/contact`                  | Contact \| Remotion Pro                     |
| Accessibility  | `/accessibility`            | Accessibility \| Remotion Pro               |
| Privacy        | `/privacy`                  | Privacy Policy \| Remotion Pro              |
| Privacy 4.0    | `/privacy-4-0`              | Privacy Policy (v4.0) \| Remotion Pro       |
| Terms          | `/terms`                    | Terms and Conditions \| Remotion Pro        |
| Terms 4.0      | `/terms-4-0`                | Terms and Conditions (v4.0) \| Remotion Pro |
| Check Mailbox  | `/check-mailbox`            | Check your mailbox \| Remotion Pro          |
| Change Email   | `/change-email`             | Confirm email change \| Remotion Pro        |

#### Authenticated Pages

| Page             | URL                               | Title                                 |
| ---------------- | --------------------------------- | ------------------------------------- |
| Dashboard        | `/dashboard`                      | Dashboard \| Remotion Pro             |
| Account Settings | `/settings`                       | Account settings \| Remotion Pro      |
| Project Overview | `/projects/[slug]`                | [Project name] \| Remotion Pro        |
| Project Info     | `/projects/[slug]/info`           | [Project name] \| Remotion Pro        |
| Project Team     | `/projects/[slug]/team`           | [Project name] \| Remotion Pro        |
| Project Perks    | `/projects/[slug]/perks`          | [Project name] \| Remotion Pro        |
| Project Usage    | `/projects/[slug]/usage`          | [Project name] \| Remotion Pro        |
| Project Settings | `/projects/[slug]/settings`       | [Project name] \| Remotion Pro        |
| Project Edit     | `/projects/[slug]/edit`           | Edit quantities \| Remotion Pro       |
| Project Delete   | `/projects/[slug]/delete`         | Delete project \| Remotion Pro        |
| Project Cancel   | `/projects/[slug]/cancel`         | Cancel subscription \| Remotion Pro   |
| Project Continue | `/projects/[slug]/continue`       | Continue subscription \| Remotion Pro |
| Reset API Keys   | `/projects/[slug]/reset-api-keys` | Reset API keys \| Remotion Pro        |
| Delete Account   | `/projects/delete`                | Delete account \| Remotion Pro        |
| Payment Success  | `/projects/[slug]?upgraded=true`  | Remotion Pro (generic)                |

#### Admin Pages

| Page            | URL              | Title                          |
| --------------- | ---------------- | ------------------------------ |
| Admin Dashboard | `/admin`         | Admin \| Remotion Pro          |
| Admin Users     | `/admin/users`   | Admin: Users \| Remotion Pro   |
| Admin Discord   | `/admin/discord` | Admin: Discord \| Remotion Pro |
| Admin Prompts   | `/admin/prompts` | Admin: Prompts \| Remotion Pro |

### Conformance Level Key

| Term                   | Definition                                            |
| ---------------------- | ----------------------------------------------------- |
| **Supports**           | Fully meets the criterion                             |
| **Partially Supports** | Some content meets, some gaps remain                  |
| **Does Not Support**   | Significant failures                                  |
| **Not Applicable**     | Feature or content type does not exist in the product |

---

## Table A: WCAG 2.1 Level A

### Principle 1: Perceivable

#### 1.1.1 Non-text Content (Level A)

**Conformance Level:** Partially Supports

**Remarks:**

- Decorative hero image: `alt=""` present
- Decorative SVG icons use `aria-hidden="true"` and `focusable="false"` throughout navbar
- Store product card cover videos: `aria-hidden="true"` (decorative, muted autoplay within link)
- Store product card cover images: `alt=""` (decorative within link, `<h2>` provides text)
- DevelopmentIcon SVG: `aria-hidden="true"` (text label adjacent)
- OpenStreetMap `<iframe>` on `/contact` has descriptive `title` attribute
- **Fixed:** Store carousel images now have descriptive `alt` text
- **Issue (NVDA-verified):** On `/store/watercolor-map` "README.md" tab: two images that function as links have no `alt` attribute — links have no accessible name
- **Issue:** Store product detail page videos lack text alternatives (no `<track>` captions)
- **Issue:** Store preview videos on `/store` contain meaningful visual information not available in text form — need text alternative
- **Issue:** Admin prompts page — video thumbnails and avatar images missing `alt` text
- **Issue:** Usage chart (Recharts `<BarChart>`) renders SVG with no `aria-label` or text alternative

#### 1.2.1 Audio-only and Video-only (Prerecorded) (Level A)

**Conformance Level:** Does Not Support

**Remarks:**

- Store product pages embed prerecorded video demos via Mux (`stream.mux.com`) with no audio descriptions or text alternatives

#### 1.2.2 Captions (Prerecorded) (Level A)

**Conformance Level:** Does Not Support

**Remarks:**

- No `<track kind="captions">` or `<track kind="subtitles">` on any `<video>` element
- Affected pages: all store product detail pages (e.g. `/store/animated-captions`)

#### 1.2.3 Audio Description or Media Alternative (Prerecorded) (Level A)

**Conformance Level:** Does Not Support

**Remarks:**

- No audio descriptions or full text alternatives provided for video content

#### 1.3.1 Info and Relationships (Level A)

**Conformance Level:** Partially Supports

**Remarks:**

- **Landmarks:** `<header>`, `<main>`, `<footer>`, `<nav>` all present on every page via `Layout/index.tsx`. All four `<nav>` elements have distinguishing `aria-label`: `"Main"` (Navbar), `"More"` (dropdown menu), `"Footer"` (Footer), `"Project"` (ProjectNav).
- **Public page form labels:**
  - Login email input has `<label>` (visually hidden) with `htmlFor`/`id` pairing
  - AmountPicker inputs have `aria-label` attributes
- **Authenticated page form labels:**
  - **Fixed (PR #503):** Dashboard entity name input has visible `<label>` with `htmlFor`/`id` pairing
  - **Fixed (PR #503):** Settings page email and name inputs now have `<label>` with `htmlFor`/`id` pairing
  - **Fixed (PR #503):** InvitationForm email input has `aria-label="Email address"`
  - **Fixed (PR #503):** InvitationForm `<Select>` role picker has `aria-label="Role"`
  - **Fixed (PR #503):** CompanyInfoForm textarea and domain input now use `<label>` with `htmlFor`/`id` pairing
  - **Issue:** Delete project confirmation input has only `placeholder` — no `<label>` element
- **Custom checkboxes — issues (browser-verified):**
  - **Issue:** Terms acceptance and Enterprise Plan checkboxes on `/projects/[slug]` are `<div>` elements with `cursor-pointer` — not exposed in accessibility tree, no `role="checkbox"`, no `aria-checked`, no keyboard access
- **Heading hierarchy:**
  - Homepage, login, store, FAQ, license, privacy all have correct h1 → h2 → h3 hierarchy
  - Project pages, admin dashboard, admin prompts have `<h1>` headings
  - **Issue:** Dashboard has two `<h1>` elements ("Licensing" and "Store Purchases")
  - **Issue:** Payment success page has no `<h1>` (starts at H2)
  - **Issue:** Admin discord page has no `<h1>` heading (source code review)
- **Project navigation (ProjectNav):**
  - **Fixed:** `<nav aria-label="Project">` with `aria-current="page"` on active link — correct pattern for page navigation links
- **Tables:**
  - Usage tables have `<thead>` and `<tbody>` structure
  - **Issue:** Usage tables lack `aria-label` or `<caption>` describing purpose (browser-verified: 2 tables)

#### 1.3.2 Meaningful Sequence (Level A)

**Conformance Level:** Supports

**Remarks:**

- DOM order matches visual order across audited pages

#### 1.3.3 Sensory Characteristics (Level A)

**Conformance Level:** Supports

**Remarks:**

- Instructions do not rely solely on sensory characteristics

#### 1.4.1 Use of Color (Level A)

**Conformance Level:** Partially Supports

**Remarks:**

- "Buy now" button uses red color to distinguish from "Learn more" — but text labels are present so color is not the sole differentiator
- License pricing tiers rely on visual layout for distinction (acceptable — text labels present)
- **Fixed:** Deleted `BlueLink`/`UnstyledLink` components. All prose links now use `.link` class or `.prose-links` container — brand blue + permanent underline. `a[target="_blank"]::after` CSS handles sr-only text. Pages flagged by Victoria now conformant.

#### 1.4.2 Audio Control (Level A)

**Conformance Level:** Supports

**Remarks:**

- Videos on store product pages do not autoplay audio

### Principle 2: Operable

#### 2.1.1 Keyboard (Level A)

**Conformance Level:** Partially Supports

**Remarks:**

- Standard links and native buttons are keyboard-accessible
- Navbar dropdown uses native `<button>` with `popovertarget` and native Popover API — fully keyboard-accessible, Escape to dismiss
- FAQ accordion uses native `<button>` inside heading — Enter/Space work natively
- Auth social login uses native `<button>` elements
- **Fixed:** ApiKeys copy and reveal buttons are native `<button>` elements with `aria-label="Copy key"` / `"Show key"` — keyboard-accessible
- **Issue (browser-verified):** License page and project page toggle switches are `<div>` elements with `onclick` — no `role`, no `tabindex`, not keyboard-focusable or operable
- **Issue (browser-verified):** License page range sliders (`input[type="range"]`) have no `aria-label` — purpose not conveyed to screen readers
- **Issue (browser-verified):** Terms and Enterprise checkboxes on project page are custom `<div>` elements — not keyboard-focusable, not in accessibility tree
- **Issue (browser-verified):** Team page remove-member button (X icon) has no accessible name

#### 2.1.2 No Keyboard Trap (Level A)

**Conformance Level:** Supports

**Remarks:**

- No keyboard traps detected. Tab moves freely through all pages.

#### 2.1.4 Character Key Shortcuts (Level A)

**Conformance Level:** Not Applicable

**Remarks:**

- No single-character keyboard shortcuts implemented

#### 2.2.1 Timing Adjustable (Level A)

**Conformance Level:** Not Applicable

**Remarks:**

- No time limits on content

#### 2.2.2 Pause, Stop, Hide (Level A)

**Conformance Level:** Supports

**Remarks:**

- Global `prefers-reduced-motion: reduce` rule disables all CSS animations, transitions, and smooth scrolling
- `InlineVideo` subscribes to `prefers-reduced-motion` via a `useReducedMotion` hook. When reduced motion is requested by the OS, auto-playing videos on `/`, `/store`, `/store/animated-captions`, `/store/watercolor-map` no longer autoplay or loop and expose native `<video controls>` so users can pause, stop, or hide motion.

#### 2.3.1 Three Flashes or Below Threshold (Level A)

**Conformance Level:** Supports

**Remarks:**

- No content flashes more than three times per second

#### 2.4.1 Bypass Blocks (Level A)

**Conformance Level:** Supports

**Remarks:**

- Skip-to-main-content link present on all pages

#### 2.4.2 Page Titled (Level A)

**Conformance Level:** Supports

**Remarks:**

- All pages have descriptive, unique `<title>` elements following the pattern "Page name | Remotion Pro"
- `/` → "Remotion Pro" (acceptable for landing page)
- Project sub-pages use dynamic titles: "[Project name] | Remotion Pro"
- Store product pages use dynamic titles: "[Product name] | Remotion Pro"
- **Remaining:** Payment success page (`/projects/[slug]?upgraded=true`) uses generic "Remotion Pro" title

#### 2.4.3 Focus Order (Level A)

**Conformance Level:** Partially Supports

**Remarks:**

- Focus order generally follows logical reading order. No `tabindex > 0` found.
- **Fixed:** `StorePurchase` component replaced `div` + `tabIndex={0}` + `role="link"` with a semantic Next.js `<Link>` (`CoolListItemLink`).
- **Issue (NVDA-verified):** On `/license`, after the "Remotion for Automators" slider, focus moves to an invisible interactive element
- **Issue (NVDA-verified):** On `/store/animated-captions` and `/store/watercolor-map`: double focus on "Purchase for $100" link — `<button>` nested inside `<a>`. Remove nested interactive elements.
- **Issue (NVDA-verified):** On `/license` under "Company License", collapsed toggle switch sections contain sliders that receive keyboard focus even though they are not visible. Exclude hidden elements from tab order.

#### 2.4.4 Link Purpose (In Context) (Level A)

**Conformance Level:** Supports

**Remarks:**

- Links have descriptive text
- External links have visual icon indicator, `target="_blank"`, and `rel="noopener noreferrer"`
- All `target="_blank"` links include `<span class="sr-only"> (opens in new tab)</span>` — `UnstyledLink` and `BlueLink` inject it automatically; plain `<a>` tags have it manually

#### 2.5.1 Pointer Gestures (Level A)

**Conformance Level:** Not Applicable

**Remarks:**

- No multi-point or path-based gestures required

#### 2.5.2 Pointer Cancellation (Level A)

**Conformance Level:** Supports

**Remarks:**

- Actions fire on click (up-event), not on down-event

#### 2.5.3 Label in Name (Level A)

**Conformance Level:** Supports

**Remarks:**

- Visible button/link labels match accessible names

#### 2.5.4 Motion Actuation (Level A)

**Conformance Level:** Not Applicable

**Remarks:**

- No motion-activated features

### Principle 3: Understandable

#### 3.1.1 Language of Page (Level A)

**Conformance Level:** Supports

**Remarks:**

- `<html lang="en">` set on all pages

#### 3.2.1 On Focus (Level A)

**Conformance Level:** Supports

**Remarks:**

- No context changes on focus

#### 3.2.2 On Input (Level A)

**Conformance Level:** Supports

**Remarks:**

- No unexpected context changes on input

#### 3.3.1 Error Identification (Level A)

**Conformance Level:** Partially Supports

**Remarks:**

- Toast notifications use `role="alert"` (test mode banner)
- **Fixed:** Login form now uses `noValidate` with Zod validation, custom error message linked via `aria-describedby` and `aria-invalid="true"`, announced with `role="alert"`
- **Issue:** Authenticated forms (dashboard project creation, settings, delete confirmation) show errors via toast only — no inline `role="alert"` or `aria-describedby` error messages
- **Issue:** InvitationForm and CompanyInfoForm lack accessible error identification

#### 3.3.2 Labels or Instructions (Level A)

**Conformance Level:** Partially Supports

**Remarks:**

- Login email input has a visually hidden `<label>` with `htmlFor`/`id` pairing
- **Fixed (PR #503):** Dashboard, settings, team invitation, company info forms now have persistent `<label>` elements or `aria-label` attributes
- **Issue:** Delete confirmation form still relies on placeholder text only — no associated `<label>` element

### Principle 4: Robust

#### 4.1.1 Parsing (Level A)

**Conformance Level:** Supports

**Remarks:**

- React-generated markup produces valid HTML
- No duplicate IDs detected
- Invalid `<button>` inside `<a>` nesting eliminated on public pages

#### 4.1.2 Name, Role, Value (Level A)

**Conformance Level:** Partially Supports

**Remarks:**

- Navbar dropdown uses native `<button>` with `aria-label` and native Popover API — proper role, focusable, Escape-dismissable
- Nav links and logo have `aria-label` attributes
- **Fixed:** Navbar, dropdown menu, Footer, and ProjectTabs all have `aria-current="page"` on the active route
- FAQ accordion has `<button>` with `aria-expanded`, `aria-controls`; panel has `role="region"` and `aria-labelledby`
- Auth social login uses native `<button>` elements with visible text labels
- **Fixed:** ProjectTabs are navigation links — `aria-current="page"` is the correct pattern (not `role="tab"`, which is for same-page content switching)
- **Fixed:** ApiKeys copy and reveal buttons have `aria-label` — accessible names provided for both icon-only buttons
- **Issue (NVDA-verified):** License/project page toggle switches are `<div>` with `data-active` and `onclick` — no `role="switch"`, no `aria-checked`, no `tabindex`, state not programmatically exposed
- **Issue (NVDA-verified):** Terms/Enterprise checkboxes are `<div>` with SVG checkmark — no `role="checkbox"`, no `aria-checked`, not in accessibility tree
- **Issue (NVDA-verified):** On `/store/animated-captions` and `/store/watercolor-map`: "Info" and "README.md" tabs are `<button>` elements without tab semantics — selected state not programmatically defined. Implement `role="tablist"` / `role="tab"` / `aria-selected`.
- **Fixed (PR #503):** Usage page period select now has `aria-label="Time period"` — accessible name no longer depends on selected option
- **Issue (NVDA-verified):** Usage chart SVGs have `role="application"` but no `aria-label` — content not described
- **Issue (NVDA-verified):** Team page remove-member button (X icon) lacks accessible name
- **Issue:** Admin prompts filter buttons lack `aria-selected` or `aria-pressed` (source code review)
- **Issue:** Admin prompts action buttons lack descriptive `aria-label` (source code review)

---

## Table B: WCAG 2.1 Level AA

### Principle 1: Perceivable

#### 1.2.4 Captions (Live) (Level AA)

**Conformance Level:** Not Applicable

**Remarks:**

- No live audio/video content

#### 1.2.5 Audio Description (Prerecorded) (Level AA)

**Conformance Level:** Does Not Support

**Remarks:**

- Store product videos have no audio description track

#### 1.3.4 Orientation (Level AA)

**Conformance Level:** Supports

**Remarks:**

- No orientation lock. Content reflows to portrait and landscape.

#### 1.3.5 Identify Input Purpose (Level AA)

**Conformance Level:** Supports

**Remarks:**

- All personal data fields have appropriate `autoComplete` attributes: login/settings/invitation email fields use `autoComplete="email"`, name field uses `autoComplete="name"`, company name uses `autoComplete="organization"`, deployment domain uses `autoComplete="url"`.

#### 1.4.3 Contrast (Minimum) (Level AA)

**Conformance Level:** Partially Supports

**Remarks:**

- Test mode banner: `color: '#7c2d12'` on orange background — passes 4.5:1
- Body text is dark on white — passes
- Disabled/inactive UI components are WCAG-exempt (e.g. disabled buttons at `opacity: 0.7`)
- **Issue:** White text on brand-blue (`#0B84F3`) primary action buttons — **3.74:1, fails 4.5:1**. Brand color constraint; affects 25+ button instances site-wide.
- **Issue:** Brand blue (`#0B84F3`) as text/link color on white backgrounds — **3.74:1, fails 4.5:1**. Affects `BlueLink`, `text-brand` links and inline text throughout public and authenticated pages.
- **Issue:** Brand blue (`#0B84F3`) on light-blue active states (`#E1F0FE`, UNDERLAY_BLUE) — **3.23:1, fails 4.5:1**. Affects active navbar item, `BlueButton` component, `CoolListItemComponent`, selected tabs/invoice rows.
- **Issue:** White text on red destructive buttons (`#ef4444`, Tailwind `red-500`) — **3.76:1, fails 4.5:1**. Affects 9 destructive action buttons (cancel subscription, delete project, remove user, etc.). Fixable: use `red-700` (`#b91c1c`, 5.12:1).
- **Fixed:** Footer text darkened from `#777777` to `#666666` — now **5.43:1** on `#F8FAFC`. (`Footer/index.tsx`)
- **Issue:** Brand blue (`#0B84F3`) text in API key `<pre>` block on near-black background (`rgba(0,0,0,0.8)`) — **3.37:1, fails 4.5:1**. Fixable: use `text-white`.
- **Issue:** Brand blue links on grey notice box background (`rgb(238,238,238)`) on `/privacy` and `/terms` — **3.23:1, fails 4.5:1**.
- **Issue:** Red warning text on `/projects/delete` on off-white background — **3.64:1, fails 4.5:1**.
- **Issue:** "Delete account" button on `/projects/delete` — white on `rgb(251,44,54)` — **3.81:1, fails 4.5:1**. Fixable: use `red-700`.
- **Issue (NVDA-verified):** "Back to homepage" link on `/contact`, `/accessibility`, `/faq` — grey #7C7D7E on #F8FAFC — **3.9:1, fails 4.5:1**.
- **Issue (NVDA-verified):** On `/projects/[slug]/usage` chart: grey #7F7F7F axis text on white (4.0:1), pink #EC4899 "Development" text (3.5:1), red #EF4444 "Failed" text (3.8:1) — all below 4.5:1.
- Full inventory: `docs/contrast-issues.md`

#### 1.4.4 Resize Text (Level AA)

**Conformance Level:** Partially Supports

**Remarks:**

- Text generally resizes up to 200% without loss of content or functionality
- **Issue (NVDA-verified):** On `/login` at 1280x1024 and 200% zoom: text "With a Remotion Pro account ... in the Remotion store" becomes invisible. All content must remain visible when page is zoomed.

#### 1.4.5 Images of Text (Level AA)

**Conformance Level:** Supports

**Remarks:**

- No images of text used (logos are exempt)

#### 1.4.10 Reflow (Level AA)

**Conformance Level:** Partially Supports

**Remarks:**

- Content generally reflows at 320px viewport width
- **Issue (NVDA-verified):** On many pages zoomed to 400% (= 320px width) the horizontal scrollbar appears, e.g. on `/contact`. Content should reflow without horizontal scroll.
- **Issue (NVDA-verified):** On `/login` at 400% zoom: text "With a Remotion Pro account ... in the Remotion store" is not visible.
- **Issue (NVDA-verified):** On `/dashboard` at 400% zoom: input placeholder text "Legal entity name (i.e. your company name)" is partially invisible.

#### 1.4.11 Non-text Contrast (Level AA)

**Conformance Level:** Partially Supports

**Remarks:**

- Most UI components have sufficient contrast
- Focus indicators present on custom inputs — `outline: 2px solid` on `:focus-visible`
- **Fixed:** On `/store/animated-captions` and `/store/watercolor-map`: grey availability status icons darkened from `rgba(0,0,0,0.2)` (~#CCCCCC, ~1.6:1) to `#767676` (4.54:1 on white) in `ProductOverview/Sidebar/styles.module.css` — meets the 3:1 non-text contrast minimum.

#### 1.4.12 Text Spacing (Level AA)

**Conformance Level:** Supports

**Remarks:**

- Content adapts to increased text spacing without loss of information

#### 1.4.13 Content on Hover or Focus (Level AA)

**Conformance Level:** Partially Supports

**Remarks:**

- Navbar popover appears on click, not hover — acceptable
- Popover uses native Popover API — dismissable via Escape key
- **Issue:** Recharts `<Tooltip>` on usage chart appears on hover with no keyboard equivalent and no Escape dismissal
- **Fixed (PR #502):** `InfoTooltip` component removed entirely from remotion.pro. On `/license`, tooltip content inlined as visible description text in expanded panels (upstream `@remotion/promo-pages` change). On `/projects/[slug]`, domain field hint inlined into placeholder.

### Principle 2: Operable

#### 2.4.5 Multiple Ways (Level AA)

**Conformance Level:** Supports

**Remarks:**

- Navigation menu and direct URL access available
- A sitemap page (`/sitemap`) is linked from the footer on all pages, providing a second navigation method alongside the main navigation menu.

#### 2.4.6 Headings and Labels (Level AA)

**Conformance Level:** Partially Supports

**Remarks:**

- Most public pages have correct heading hierarchy (h1 → h2 → h3)
- Project pages, admin dashboard, admin prompts have `<h1>` headings
- **Issue (browser-verified):** Dashboard has two `<h1>` elements
- **Issue (browser-verified):** Payment success page starts at H2 (no H1)
- **Issue:** Admin discord page has no `<h1>` heading (source code review)
- **Fixed (PR #503):** CompanyInfoForm now uses `<label>` elements with `htmlFor`/`id` pairing instead of `<h2>`

#### 2.4.7 Focus Visible (Level AA)

**Conformance Level:** Partially Supports

**Remarks:**

- CoolInput: `focus-visible` outline present
- AmountPicker: `focus-visible` outlines and `aria-label` present
- Standard form elements inherit browser default focus styles
- **Issue (NVDA-verified):** On `/login` keyboard focus is not visible on "Let's go!" button. Same on `/dashboard` with "Create" and "Explore the Store" buttons.
- **Issue (NVDA-verified):** On `/projects/[slug]` the "-" and "+" quantity buttons in expandable sections have no visible keyboard focus. Same on `/projects/[slug]/edit`.
- **Issue (NVDA-verified):** On `/projects/[slug]/team` keyboard focus is not visible on "x" remove-member buttons.
- **Issue (NVDA-verified):** On `/store/animated-captions` and `/store/watercolor-map` "README.md" tab: permalinks are focusable but invisible when they receive focus.

### Principle 3: Understandable

#### 3.1.2 Language of Parts (Level AA)

**Conformance Level:** Not Applicable

**Remarks:**

- Content is entirely in English. No sections in other languages.

#### 3.2.3 Consistent Navigation (Level AA)

**Conformance Level:** Supports

**Remarks:**

- Navbar and footer appear consistently across public pages
- Authenticated pages use consistent ProjectShell layout with ProjectTabs

#### 3.2.4 Consistent Identification (Level AA)

**Conformance Level:** Supports

**Remarks:**

- Components with same function use consistent labels across pages

#### 3.3.3 Error Suggestion (Level AA)

**Conformance Level:** Partially Supports

**Remarks:**

- Login form: invalid email format does not provide suggestion for correction
- **Issue:** Authenticated forms rely on toast notifications for error feedback — no inline error suggestions near the relevant fields

#### 3.3.4 Error Prevention (Legal, Financial, Data) (Level AA)

**Conformance Level:** Partially Supports

**Remarks:**

- Financial transactions (Stripe checkout) occur on Stripe's hosted pages, outside scope of this product
- Delete project page requires typing a confirmation phrase before deletion — good
- **Issue:** Delete confirmation input lacks accessible label and instructions (placeholder only)

### Principle 4: Robust

#### 4.1.3 Status Messages (Level AA)

**Conformance Level:** Partially Supports

**Remarks:**

- Test mode banner uses `role="alert"` — announces to screen readers
- **Issue:** Loading states across authenticated pages (dashboard, usage chart, API keys) show skeleton loaders without `aria-busy="true"` or `aria-live="polite"` announcements
- **Issue:** Async operation results (project creation, settings updates, copy-to-clipboard) rely on toast library — no guaranteed `aria-live` region
- **Issue:** Chart data loading completion not announced to screen readers

---

## Accessibility Statement

A public [Accessibility Statement](/accessibility) is available on the Remotion Pro website, declaring conformance goals, known limitations, and contact information for accessibility feedback.

---

## Summary of Issues

### Does Not Support

| Criterion           | Issue                                               | Affected Pages             |
| ------------------- | --------------------------------------------------- | -------------------------- |
| 1.2.1, 1.2.2, 1.2.3 | Videos lack captions and descriptions               | Store product detail pages |
| 1.2.5               | No audio descriptions for video                     | Store product detail pages |
| 2.4.5               | No second navigation method (no search, no sitemap) | Site-wide                  |

### Partially Supports — NVDA-Verified Findings (External Audit, March 2026)

| Criterion | Issue                                                                                                                                                                             | Affected Pages / Components                                               |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| 1.1.1     | Image-links on product pages lack alt text                                                                                                                                        | `/store/watercolor-map`                                                   |
| 1.4.1     | ~~Inline links distinguished only by color~~ **Fixed:** `.link` / `.prose-links` CSS classes add permanent underline                                                              | `/privacy`, `/store/watercolor-map`, `/store/animated-captions`           |
| 1.4.3     | Multiple contrast failures — brand blue, grey links, chart colors                                                                                                                 | Site-wide — see `docs/contrast-issues.md`                                 |
| 1.4.4     | Text invisible at 200% zoom on login page                                                                                                                                         | `/login`                                                                  |
| 1.4.10    | Horizontal scroll at 400% zoom (320px width)                                                                                                                                      | `/contact`, `/login`, `/dashboard`                                        |
| 1.4.11    | ~~Grey status icons fail 3:1 non-text contrast~~ **Fixed:** `.denyicon` color set to `#767676` (4.54:1 on white)                                                                  | `/store/animated-captions`, `/store/watercolor-map`                       |
| 1.4.13    | ~~Tooltips not dismissible via Escape, not keyboard-accessible~~ **Fixed (PR #502):** `InfoTooltip` removed entirely                                                              | `/license`                                                                |
| 2.1.1     | Toggle switches are `<div>` — not keyboard-accessible                                                                                                                             | `/license`, `/projects/[slug]`                                            |
| 2.1.1     | Custom checkboxes are `<div>` — not keyboard-accessible                                                                                                                           | `/projects/[slug]` (Terms, Enterprise)                                    |
| 2.2.2     | ~~Auto-playing videos have no pause/stop/hide mechanism~~ **Fixed:** `InlineVideo` honors `prefers-reduced-motion` — disables autoplay/loop and exposes native `<video controls>` | ~~`/`, `/store`, `/store/animated-captions`, `/store/watercolor-map`~~    |
| 2.4.3     | Focus moves to invisible elements; nested `<button>` inside `<a>`                                                                                                                 | `/license`, `/store/animated-captions`, `/store/watercolor-map`           |
| 2.4.7     | Focus indicator not visible on multiple buttons                                                                                                                                   | `/login`, `/dashboard`, `/projects/[slug]`, `/projects/[slug]/team`       |
| 4.1.2     | Toggles lack `role="switch"` / `aria-checked`                                                                                                                                     | `/license`, `/projects/[slug]`                                            |
| 4.1.2     | Checkboxes not in accessibility tree — no `role="checkbox"`                                                                                                                       | `/projects/[slug]` (Terms, Enterprise)                                    |
| 4.1.2     | Tab components lack `role="tab"` / `aria-selected`                                                                                                                                | `/store/animated-captions`, `/store/watercolor-map`                       |
| 4.1.2     | Comboboxes use first option as pseudo-label — **Partially fixed (PR #503):** Usage period select has `aria-label`                                                                 | `/projects/[slug]/team`                                                   |
| 4.1.2     | Team remove button (X) has no accessible name                                                                                                                                     | `/projects/[slug]/team`                                                   |
| 4.1.3     | Dynamic price updates and "Copied to clipboard" not announced                                                                                                                     | `/projects/[slug]`, `/projects/[slug]/usage`                              |
| 1.3.1     | ~~Form inputs missing `<label>` elements~~ **Fixed (PR #503):** All form inputs now have `<label>` or `aria-label`                                                                | ~~`/dashboard`, `/projects/[slug]`, `/projects/[slug]/edit`, `/license`~~ |
| 1.3.1     | Headings not marked up (license tiers, project form sections)                                                                                                                     | `/license`, `/projects/[slug]`, `/dashboard`                              |
| 1.3.1     | Lists not using semantic `<ul>`/`<li>` markup                                                                                                                                     | `/license`, `/projects/[slug]`                                            |
| 1.3.1     | Usage tables lack `<caption>` or `aria-label`                                                                                                                                     | `/projects/[slug]/usage`                                                  |
| 3.3.1     | ~~Login uses browser-native validation~~ **Fixed:** Custom Zod validation with `aria-describedby` and `role="alert"`                                                              | `/login`                                                                  |

### Additional Issues — Previous Code-Level Audit

| Criterion | Issue                                                     | Affected Pages / Components      |
| --------- | --------------------------------------------------------- | -------------------------------- |
| 2.1.1     | Range sliders have no `aria-label`                        | `/license`                       |
| 2.4.2     | Payment success page uses generic title                   | `/projects/[slug]?upgraded=true` |
| 1.1.1     | Mux logo missing `alt` attribute                          | `/projects/[slug]/perks`         |
| 1.1.1     | Usage chart SVG lacks text alternative                    | `/projects/[slug]/usage`         |
| 3.3.1     | Errors shown via toast only — no inline accessible errors | All authenticated forms          |
| 1.4.13    | Chart tooltip not keyboard-accessible                     | `/projects/[slug]/usage`         |
| 1.1.1     | Admin prompts thumbnails/avatars missing `alt`            | `/admin/prompts`                 |
| 2.4.6     | Admin discord page missing `<h1>` heading                 | `/admin/discord`                 |
