Pressroom application: Accessibility Conformance Report
WCAG edition, based on VPAT® 2.5 (Rev, WCAG 2.2).
Name of product and version
Pressroom application: the web pages Pressroom serves, in two scopes that are rated separately.
- Staff application: the editorial web app that editors, contributors,
publishers and administrators sign in to:
src/app/(auth)(sign-in, password reset, two-factor, invite and join) andsrc/app/(dashboard)(every signed-in page). The former in-app marketing pages (/about,/welcome) were retired when the public site moved to pressrooom.com, a separate site this report does not cover; both paths now redirect there. - Reader pages: the public pages a newsletter's readers reach:
src/app/(reader)(/subscribe,/n/[slug]/subscribe,/archive,/n/[slug]/archive,/n, the reader 404 and error pages), the subscription confirmation/subscribe/confirm/[token], the unsubscribe and preference pages under/u(/u/[token],/preferences,/stay,/one-click,/u/digest/[token],/u/manage,/u/test/[token]), the web views/v/[token]and/v/test/[token], the shared preview/p/[token], the poll vote, thank-you and survey pages (/api/polls/[id]/vote), the archived edition pages, and the accessibility statement/accessibility.
The body of a newsletter edition, where a reader page shows it (archived
edition, /v, /p), is the email's own HTML and is rated in
email-acr.md. This report rates the page around it: its
title, language, landmarks, headings, navigation bar and the notices those
routes serve.
Version: main at 5a87a62c (2026-11-01). This is version 5 of the report.
Version 1 rated main at 7e5a5dd7 (2026-10-26), version 2 main at
b0c28c6d (2026-10-27), version 3 main at 56733a0f (2026-10-31) and
version 4 main at ab9ca8fc (2026-11-01); all four are in the repository
history, and "What changed since version 1" to "since version 4" under
Notes list what moved.
Report date
Version 1 2026-10-26; version 2 2026-10-27; version 3 2026-11-01; version 4 2026-11-01; version 5 2026-11-01. Last reviewed 2026-11-01.
Product description
Pressroom is a multi-tenant newsletter editorial platform. Staff draft and
review articles, assemble editions on a board and a canvas, check and send
them, and manage subscribers, templates and integrations. Readers subscribe,
confirm, change their preferences or unsubscribe, read past editions in a
public archive and vote in polls. The staff application is a Next.js app built
on shadcn/ui and Base UI primitives with a TipTap editor and drag-and-drop
boards. The reader pages are small server-rendered pages: Next pages under
(reader) and HTML that route handlers write directly (src/lib/unsubscribe/pages.ts,
src/lib/subscribers/confirm-page.ts, src/lib/reader/web-edition.ts,
src/app/api/polls/[id]/vote/route.ts).
The two scopes have different evidence and different results, so each criterion row gives one rating per scope.
Contact information
Report accessibility problems through the route on the public statement page
/accessibility (the deployment's HELP_URL, or the newsletter's contact
address on a newsletter's own host). Issues are tracked in the Pressroom
repository (Gitea chris/pressroom, umbrella #2122).
Notes
- Self-authored. Nobody outside the project has audited the application. A third-party audit is planned only if a procurement process asks for one (owner decision #1352 D-4).
- No screen reader has been used yet, on either scope. Every keyboard
verdict comes from synthetic key events in Playwright or in component
tests, and every "what a screen reader is given" verdict comes from the
accessibility tree (Playwright
ariaSnapshot()), component tests and source review. Nobody has listened to these pages with NVDA, JAWS or VoiceOver. That pass is an owner step: for the reader pages the script is written (sr-script-reader.md, target 2026-12-15, #2139); for the staff application it is planned now that the #2138 fixes are in (target 2027-04-02). Rows whose outcome depends on what is announced (4.1.2, 4.1.3, 2.4.3) say so, and a Supports in those rows means "no known defect in what the accessibility tree and the code expose", not "heard and confirmed". - How ratings were given. "Supports" is used only where source review
and a runtime check (axe in
e2e/a11y.spec.tsore2e/a11y-scroll-regions.spec.ts, the 2026-10 reader re-audit's keyboard walk, a measurement, or a component test that renders the fixed component and asserts its role, name, state or key handling) agree and no audit finding against the criterion is open. A criterion with anopenorpartlyfinding on this version is never rated Supports. An axe pass on its own was not taken as proof. A fix that exists only in an open pull request does not count: its row is rated asmainstands and names the PR. - Not Evaluated at A and AA. VPAT 2.5 reserves "Not Evaluated" for AAA. This report also uses it at A and AA, for the few criteria nobody has tested on this product, because any other rating would claim a result that no evidence supports. Each such row names the check that would settle it and its target date.
- Content is the customer's. Staff write the articles, choose the images and alt text, and set some colors (newsletter branding). Where an outcome depends on that content, the remark says so.
- What changed since version 1. Version 1 rated
mainat 7e5a5dd7 and did not count tranche C (#2336) or the/vweb-copy structure (#2337), which were open pull requests then. Both are onmainat this version, together with the kanban card's visible Delete item (#2348, UI-23),/submitas a real form (#2350, UI-36), the subscribe form's in-page address check (#2360, RD-10), batch D (#2362: UI-09, UI-10, UI-42, UI-55, UI-56) and batch E (#2365: UI-11, UI-19, UI-24). Every reader finding (RD-01 to RD-13) is fixed; on the #2138 checklist only UI-08 is still unticked. Re-rating found three new staff findings, UI-57 to UI-59 (Known limitations, item 3). The reader and email accessibility gate (#2144, PR #2369) is an open pull request at this version and is not counted. - What changed since version 2. Version 3 re-rates only the five staff
rows that UI-08, UI-58 and UI-59 held at Partially Supports (#2609, a
child of #2529): 1.3.1, 1.4.3, 1.4.11, 2.4.6 and 2.5.7 are Supports on
this version. The fixes merged after version 2 was rated: #2376 (UI-08:
opacity stacks, status dots and chart marks measured, held by
non-text-contrast.test.ts), #2375 (UI-58: the/articles/[id]h1 and named rails, the/settings/healthheading order, and strict staff scans), #2398 (UI-59: Narrower and Wider buttons on kanban columns; UI-60: readiness words beside the dots and bars) and #2404 (UI-61: the team analytics bands at 3:1). #2609 also replaces the last nine decorative opacity stacks with the solid--muted-foreground, so the stack check waives none. #2375 also wired the forms UI-57 names; the rows that finding holds (3.3.1, 3.3.3, 4.1.3) are not re-rated in this version and keep version 2's rating. - What changed since version 3. Version 4 re-rates only the three staff
rows UI-57 held, against
mainat ab9ca8fc. #2375 (UI-57) tied the errors of the forms #2365 left alone to their fields; 3.3.1 and 3.3.3 are Supports on this version. 4.1.3 stays Partially Supports: the proof dialog's address check shows its error as you type, in no live region (UI-62, new). - What changed since version 4. Version 5 re-rates only the staff 4.1.3
row, against
mainat 5a87a62c. #2630 (UI-62, #2629) gives the proof-send dialog's address check a politerole="status"region, so the staff row is Supports on this version; like every row that depends on what is announced, it is not yet heard with a screen reader (the staff pass, target 2027-04-02). Version 5 also re-checked, onmain, that the other staff forms the row names still announce their status messages. UI-62 leaves the known limitations and 4.1.3 the remediation targets.
Evaluation methods used
Editorial UI audit, 2026-09-13 (
11-audit/ui-accessibility-audit-2026-09-13.md). WCAG 2.2 AA; axe-core 4.11.3 via Playwright over 35 reachable routes in light and dark, a 390 px pass, a scripted keyboard sweep, and a source review in five areas. 54 consolidated findings UI-01 to UI-54 (4 critical, 22 serious, 18 moderate, 10 minor). No screen reader.Triage of those findings, 2026-10-26 (#2136,
ui-audit-triage-2026-10.md, checked againstmainat 5b2ed029 by source re-reading): 8 closed, 29 partly, 14 open, 3 obsolete. It also lists the coverage gaps reused under Known limitations.Fixes since the triage, on this version, read from the merged PRs and the #2138 checklist (the finding status this report uses):
- tranche A (#2324):
--ringand--inputat 3:1, a solid 2 px focus ring,color-scheme, contrast of the destructive, affirmative and read-more colors, every icon-only button named, andButtonicon sizes that require a label at the type level; - tranche B (#2327):
aria-modalon dialogs, the triage deck and template modal as real dialogs, settings and editor controls labeled, upload errors announced, guided-mode and triage-deck announcements, field-named validator messages, group labels, row-specific control names, presence names; - tranche C (#2336):
aria-currentandaria-pressedfor painted state, comment marks asrole="mark", a section picker below 1024 px on article types, the APG tabs pattern andaria-expandeddisclosures,CardTitleas a heading and amainon the auth pages, sr-only state text on health dots, no button inside a link, noaria-labelon generic elements, chart and histogram summaries, the empty/assemblyslot as a real button with a menu, DOM focus in the Ready queue and ideas list, scoped single-key shortcuts with an off switch, Move up / Move down on the social queue, sections and blocks,aria-current="date"on the calendar, named strip slots, a keyboard column splitter, Shift+F10 in the kanban help, and table semantics on the people roster and social queue; - #2348 (Delete… in the kanban card's visible Move-to menu) and #2350
(
/submitas a<form>); - batch D (#2362): palette text in both themes, held by a new calculation
over every class string, the
/auditactor chips measured, 24 px drag and resize targets, a presence pulse that stops after 4 s, and a<title>onglobal-error.tsx; - batch E (#2365): errors tied to their fields on the forms it lists, table semantics on the kanban and calendar grids, and the UI-24 runtime check below.
Their tests include
src/lib/__tests__/design-token-contrast.test.ts,src/lib/__tests__/palette-text-contrast.test.ts,src/components/__tests__/icon-button-names-2138.test.tsx,src/components/__tests__/a11y-forms-overlays-2138.test.tsx,src/components/__tests__/a11y-state-reorder-2138c.test.tsx,src/components/__tests__/a11y-forms-2138e.test.tsx,src/components/articles/__tests__/kanban-board-table.test.tsx,kanban-board-keys.test.tsx,kanban-card-actions.test.tsx,kanban-target-size.test.tsxandsubmit-form-2335.test.tsx, and, for this version,src/components/__tests__/acr-app-v2-checks.test.tsx(health-dot state text and chart names, which had no test of their own).- tranche A (#2324):
Reader-page re-audit, 2026-10-26 (#2137,
reader-reaudit-2026-10.md, onmainat 5b2ed029): axe-core 4.14.0 at serious through minor on 46 route states, at 1280 and 390 px, in both color schemes (184 runs); reflow at 320 px; a keyboard walk measuring order, viewport and focus-indicator contrast at every stop; scripted keyboard flows; the accessibility tree and<title>of each route. Thirteen findings RD-01 to RD-13, then the "Status after #2139" table for the fixes in #2331, #2337 and #2360, all marked fixed.Regression scan in CI,
e2e/a11y.spec.ts: axe with the tagswcag2a wcag2aa wcag21a wcag21aa wcag22aa best-practice, blocking on serious and critical, logging moderate and minor. It scans about 30 staff routes in both themes and the reader routes at 1280 and 390 px (list under Known limitations), and asserts the/vand/v/teststructure (onemainholding an h1, no unhidden empty paragraph) and the subscribe form's in-page error. On this version's run onmain(CI run 8667, b0c28c6d, green) the logged moderate and minor findings were on staff routes only:heading-orderon/settings/health, andlandmark-uniqueandpage-has-heading-oneon/articles/[id], in both themes (UI-58). Since #2375 the staff and auth scans are strict as well: a moderate finding fails the job, andMODERATE_ALLOW_LISTis empty, so on version 3 those three rules pass on both routes in both themes.e2e/a11y-scroll-regions.spec.ts(#2365) stages enough stories and ideas that every inner scroll region on/pipeline(both views),/assemblyand/ideasoverflows, then runs axe'sscrollable-region-focusable: 12 regions judged, none unreachable (UI-24).Source review for this report. Version 1:
autoCompleteon the sign-in, account and subscribe forms, session lifetime (src/lib/auth/config.ts), andaria-modalonsrc/components/ui/dialog.tsx. Version 2, on b0c28c6d: each fix the #2138 and #2139 checklists tick, re-read in the files their PRs changed; the forms #2365 left alone because batch D was changing their files; the kanban column splitter's pointer handling (src/components/articles/kanban-column.tsx); the remainingtext-muted-foreground/NNopacity sites (UI-08); and the remaining infinite animations (loading skeletons and progress steps). Version 4, on ab9ca8fc: every form #2375 lists for UI-57, re-read onmainfor the field the error marks (aria-invalid), what describes it (aria-describedby), how the message is announced and what it tells the user to do (the 3.3.1, 3.3.3 and 4.1.3 rows name the files). Version 5, on 5a87a62c: proof-send'sProofAddressAnnouncer(src/components/newsletter/proof-send.tsx), and again each staff form the 4.1.3 row names for how its status message is announced (the alerts, live statuses and toasts listed there, the settings save bar'srole="status"and theToasterthe dashboard mounts).
Applicable standards and guidelines
| Standard / guideline | Included in report |
|---|---|
| WCAG 2.0 Level A | Yes (as part of 2.2) |
| WCAG 2.0 Level AA | Yes (as part of 2.2) |
| WCAG 2.1 Level A | Yes |
| WCAG 2.1 Level AA | Yes |
| WCAG 2.2 Level A | Yes |
| WCAG 2.2 Level AA | Yes |
| WCAG 2.2 Level AAA | No |
Conformance target: WCAG 2.2 Level AA. The legal bar this report is most often read against is WCAG 2.1 Level AA (ADA Title II, below). Every 2.1 A and AA criterion is a 2.2 criterion, except 4.1.1 Parsing, which 2.2 removed and which is listed anyway. The six criteria new in 2.2 are marked (2.2 only) in the tables, so the 2.1 AA result is the tables with those rows left out. The summary gives both.
Neither scope conforms to WCAG 2.1 AA or 2.2 AA on this version. The reader pages have no open audit finding; what stands between them and 2.1 AA is language of parts (3.1.2), four criteria not yet evaluated (five at 2.2), and the screen-reader pass. The staff application rates 2 criteria Partially Supports (2 at 2.1 AA) and none Does Not Support; six criteria are not yet evaluated (three at 2.1 AA).
Terms
- Supports: the functionality of the product has at least one method that meets the criterion without known defects, or meets it with an equivalent facilitation.
- Partially Supports: some functionality of the product does not meet the criterion.
- Does Not Support: the majority of product functionality does not meet the criterion.
- Not Applicable: the criterion is not relevant to the product.
- Not Evaluated: the product has not been evaluated against the criterion (see Notes on its use at A and AA).
Summary
WCAG 2.2
| Staff A | Staff AA | Reader A | Reader AA | |
|---|---|---|---|---|
| Supports | 25 | 16 | 22 | 14 |
| Partially Supports | 0 | 2 | 0 | 1 |
| Does Not Support | 0 | 0 | 0 | 0 |
| Not Applicable | 5 | 2 | 9 | 5 |
| Not Evaluated | 2 | 4 | 1 | 4 |
WCAG 2.1 AA (2.2-only rows left out)
| Staff A | Staff AA | Reader A | Reader AA | |
|---|---|---|---|---|
| Supports | 25 | 13 | 21 | 12 |
| Partially Supports | 0 | 2 | 0 | 1 |
| Does Not Support | 0 | 0 | 0 | 0 |
| Not Applicable | 5 | 2 | 9 | 3 |
| Not Evaluated | 0 | 3 | 0 | 4 |
WCAG 2.2 report
Columns: the staff application's rating, then the reader pages'. Finding IDs
are UI-nn (triage memo and the #2138 checklist) and RD-nn (reader
re-audit). Target dates for every row below Supports are collected under
Known limitations.
Table 1: Success Criteria, Level A
| Criteria | Staff application | Reader pages | Remarks and explanations |
|---|---|---|---|
| 1.1.1 Non-text Content | Supports | Supports | Staff: icon-only buttons are named (UI-13, #2324) and presence avatars name the person (UI-53, #2327). Since version 1 (#2336): the readiness bar is aria-hidden beside the count text that says the same; the settings sparklines and bar charts are role="img" named by their data, not their chart type; the audit histogram is role="img" with a summary (UI-50); readiness dots and sidebar counts use role="img" or sr-only text instead of an aria-label on a generic element (UI-47). axe passes at serious on every scanned staff route in both themes; the chart names are asserted in acr-app-v2-checks.test.tsx. The histogram is on /audit, which the CI scan does not reach (source review). Alt text on uploaded images is the editor's. Reader: axe image-alt passes on every reader route in both schemes; images in an edition body are rated in the email ACR. |
| 1.2.1 Audio-only and Video-only (Prerecorded) | Not Applicable | Not Applicable | No page plays audio or video (no <audio> or <video> in src/app or src/components). |
| 1.2.2 Captions (Prerecorded) | Not Applicable | Not Applicable | As 1.2.1. |
| 1.2.3 Audio Description or Media Alternative (Prerecorded) | Not Applicable | Not Applicable | As 1.2.1. |
| 1.3.1 Info and Relationships | Supports | Supports | Staff: fixed: settings and editor controls have programmatic labels (UI-04, UI-12); checkbox and radio sets are labeled groups (UI-48); the people roster, social queue, kanban grids (by section and by assignee) and calendar month and week grids are tables with row and column headers (UI-19, #2336, #2365, kanban-board-table.test.tsx, calendar-board.test.tsx); CardTitle renders a heading, the auth pages have an h1 inside a main, and sidebar groups are labeled (UI-32, UI-44); health dots carry state text (UI-38); comment marks are role="mark" (UI-21); empty strip slots are named (UI-43); errors on the forms #2365 lists are tied to their fields (UI-11). Since version 2, /articles/[id], the article editor, has one h1 (the workspace header's story name; the read-only headline is an h2) and its rails are named landmarks ("Path to publish", "Steps"), and the day-zero /settings/health heading is an h2 (UI-58, #2375, workspace-header.test.tsx); the strict staff scan fails on page-has-heading-one, landmark-unique and heading-order there. Reader: forms use fieldset/legend and labeled fields (re-audit "What passed"); survey legends are numbered from 1 (RD-12, #2331); archived editions, /p, /v/[token] and /v/test/[token] have one main, a hidden h1 and hidden spacer paragraphs (RD-05, RD-11, #2331, #2337), which e2e/a11y.spec.ts asserts on /v and /v/test. |
| 1.3.2 Meaningful Sequence | Supports | Supports | Staff: DOM order is reading order; no finding against 1.3.2 in the 2026-09 audit. Reader: the keyboard walk found Tab order matching visual order on every route (0 upward jumps), and the accessibility tree reads in visual order. |
| 1.3.3 Sensory Characteristics | Supports | Supports | Staff: no finding; instructions name controls, not shapes or positions. Reader: RD-08 ("Tap one answer" with nothing to tap) is fixed on archived editions, /p (#2331), /v and /v/test (#2337): web copies read "Voting is in the email." (web-view-structure.test.ts). |
| 1.4.1 Use of Color | Supports | Supports | Staff: fixed: kanban card status has sr-only text and icon labels (UI-23), the caption limit has a text suffix (UI-34); since version 1 (#2336), calendar "today" has aria-current="date" and ", today" in its name (UI-18), selected state in the sidebar, layout cards, audit presets, ideas pills and the kanban "My articles" toggle is exposed as aria-current or aria-pressed (UI-20), health dots carry state text (UI-38) and comment marks a role and description (UI-21). Unit tests assert each (sidebar-newsletters.test.tsx, calendar-board.test.tsx, a11y-state-reorder-2138c.test.tsx, acr-app-v2-checks.test.tsx). Reader: axe link-in-text-block passes on every route; status and errors are text. |
| 1.4.2 Audio Control | Not Applicable | Not Applicable | No audio. |
| 2.1.1 Keyboard | Supports | Supports | Staff: kanban cards take focus and have a visible "Move to…" menu that now ends with Delete… (UI-23, #2348, keyboard path tested in kanban-card-actions.test.tsx); /assembly has "Place in…", and its empty slot is a real button whose menu offers the top candidates (UI-02, #2336, e2e/pipeline.spec.ts); the social queue, /output sections and the block builder reorder with Move up / Move down or a Move menu (UI-17); kanban columns resize with the arrow keys, Home and End (UI-51); the palette, crop editor, triage deck and template modal are real dialogs (UI-01, UI-14). Calendar day cells stay click-only, with the page's keyboard "New issue" button as the route the triage memo accepts (UI-18). Inner scroll regions hold tabbable content, and axe finds none unreachable at runtime (UI-24, e2e/a11y-scroll-regions.spec.ts). No finding against 2.1.1 is open. Key handling is tested in components (jsdom), not in a browser keyboard walk of the staff app. Reader: Tab reached every control on every route; every form submits with Enter; radio groups take arrow keys (re-audit). |
| 2.1.2 No Keyboard Trap | Supports | Supports | Staff: the palette trap is gone (UI-01); dialogs trap focus by design and close with Escape (Base UI, UI-14 tests in a11y-forms-overlays-2138.test.tsx). Reader: no trap on any route (re-audit keyboard walk). |
| 2.1.4 Character Key Shortcuts | Supports | Not Applicable | Staff: fixed since version 1 (UI-16, #2336): the ideas list and triage deck bind their letter keys to their own region or dialog, not window, and skip inputs, selects, comboboxes, contentEditable and modified keys; every single-key shortcut, including the kanban's page-wide / ? j k h l, can be turned off with a per-browser switch (kanban help dialog, and "Letter keys on/off" under the ideas list). Kanban digit moves only act on a focused card. Tested in a11y-state-reorder-2138c.test.tsx, kanban-board-keys.test.tsx and ideas-start-editing-ai.test.tsx. Reader: no shortcuts. |
| 2.2.1 Timing Adjustable | Supports | Not Applicable | Staff: error and warning toasts persist until dismissed and have a close button (UI-46); the sign-in session lasts 7 days and is extended on use (src/lib/auth/config.ts), beyond the criterion's 20-hour exception. Reader: no time limits within a page. Signed links expire, which is not a time limit on an activity in progress. |
| 2.2.2 Pause, Stop, Hide | Supports | Not Applicable | Staff: the presence badge pulses twice (4 s) and then stays still, and not at all under reduced motion (UI-55, #2362, presence-indicator.tsx, tested in a11y-forms-overlays-2138.test.tsx); it pulses again only when someone new joins. The other pulsing elements are loading placeholders and the progress step of a running generation, which last only while the page cannot be used for that task. Reader: no moving or auto-updating content; animation in an edition body is rated in the email ACR. |
| 2.3.1 Three Flashes or Below Threshold | Supports | Supports | Nothing in either scope flashes. Uploaded images are rated in the email ACR. |
| 2.4.1 Bypass Blocks | Supports | Supports | Staff: the dashboard has a skip link to main#content (nav-a11y.test.tsx), and the auth pages are a main (UI-44). Reader: the Next pages and route-handler pages have one main, poll pages since RD-06 (#2331), and /v/[token] and /v/test/[token] since RD-05 (#2337, asserted in e2e/a11y.spec.ts). |
| 2.4.2 Page Titled | Supports | Supports | Staff: every page exports a title on the %s · Pressroom template, held by src/lib/__tests__/page-titles.test.ts (UI-06), and global-error.tsx now sets "Something went wrong" (UI-56, #2362, error-pages.test.tsx). Reader: the reader 404 reads "Page not found" (RD-02, #2331, asserted in e2e/a11y.spec.ts), an unknown archived edition answers an HTML page with a title (RD-07), and the preferences outcome leads the title (RD-03). |
| 2.4.3 Focus Order | Supports | Supports | Staff: dialogs move focus in and back and are aria-modal (UI-14, UI-28); guided-mode steps focus the new heading (UI-33); since version 1 the Ready queue and the ideas list move DOM focus with j/k, not a painted ring (UI-03, #2336, ideas-start-editing-ai.test.tsx), and a cancelled kanban delete returns focus to the card (#2348). Not yet confirmed with a screen reader: whether a screen reader's virtual cursor can leave a modal dialog is part of the staff screen-reader pass (UI-28's remaining check). Reader: Tab order matches visual order on every route; after a subscribe, focus moves to the outcome (RD-04, #2331). Not yet confirmed with a screen reader. |
| 2.4.4 Link Purpose (In Context) | Supports | Supports | Staff: every icon-only link and button is named (UI-13, #2324; the Button type requires a name for icon sizes); the setup links that opened new tabs are gone (UI-52). Reader: the shared preview's placeholder links are now text (RD-09, #2331). Links in an edition body are rated in the email ACR. |
| 2.5.1 Pointer Gestures | Supports | Not Applicable | Staff: no path-based or multipoint gesture is required. Dragging is covered under 2.5.7; the crop area also has a zoom slider and arrow keys (UI-37). Reader: no gestures. |
| 2.5.2 Pointer Cancellation | Supports | Supports | Native buttons and links, which activate on the up-event; no down-event actions found in either audit. |
| 2.5.3 Label in Name | Supports | Supports | Staff: names given to visible-text controls start with the visible text, for example "Save Mautic settings" for "Save" (UI-49, #2327). Reader: every control's accessible name is its visible label (accessibility tree). |
| 2.5.4 Motion Actuation | Not Applicable | Not Applicable | No motion-triggered functionality. |
| 3.1.1 Language of Page | Supports | Supports | Staff: <html lang="en"> in the root layout and in global-error.tsx (UI-26); the interface is English only. Reader: lang on every document, the newsletter's language on web copies (#1724). |
| 3.2.1 On Focus | Supports | Supports | Nothing changes context on focus in either audit. |
| 3.2.2 On Input | Supports | Supports | Staff: settings that save on change stay on the page; no select or checkbox navigates. Reader: the preference checkboxes change nothing until Save (re-audit scripted flow). |
| 3.2.6 Consistent Help (2.2 only) | Not Evaluated | Not Evaluated | Neither audit checked where help and contact links sit across pages. To be checked with the remaining manual items (target 2027-01-29). |
| 3.3.1 Error Identification | Supports | Supports | Staff: the shared Field (src/components/ui/field.tsx) wires aria-invalid and aria-describedby; sign-in, invite and join errors are alerts; upload errors are alerts (UI-11, #2327); the caption limit and /submit expose invalid state, and /submit is now a noValidate form (UI-34, UI-36, #2350); #2365 tied the errors of the forms it lists (new newsletter, article-type tasks, restore, import and undo import, feeds, the new-issue dialog, two-factor sign-in and others) to their fields (a11y-forms-2138e.test.tsx). Since version 3, the forms #2365 left alone are wired the same way (UI-57, #2375): the field an error is about is aria-invalid and described by the message. A component test asserts it for the newsletter due-date lead time and spam-score lines, the custom web address, subscriber attributes and the automation rule dialog, including focus and clearing on edit (a11y-forms-2138-ui57.test.tsx); source review on ab9ca8fc confirms it for the template editor's name, key and MJML fields (structure-tab.tsx), the poll card's question and options, the add-idea dialog's body, URL and HTML fields, manual send's date and count, population shares, proof-send's other addresses, and the issue title, subject and preview text. #2375 found nothing to tie in the media picker and the other batch D files (request-level errors already alerts or toasts). Reader: a mistyped or empty address is caught before posting with the server's rule; the field gets aria-invalid and aria-describedby, the role="alert" message shows and focus moves to the field (RD-10, #2360, subscribe-form-validation.test.tsx and e2e/a11y.spec.ts); the server-side error is the same alert. |
| 3.3.2 Labels or Instructions | Supports | Supports | Staff: settings, kanban search, social caption and crop area are labeled or described (UI-04, UI-12, UI-37, #2327); the kanban help dialog lists Shift+F10 and the Menu key for the card menu (UI-54, #2336), and Delete is also in the visible Move-to menu (#2348). Reader: RD-12 and RD-08 fixed on every web copy (#2331, #2337). |
| 3.3.7 Redundant Entry (2.2 only) | Not Evaluated | Supports | Staff: the multi-step flows (submission wizard, guided mode, imports) were not checked for re-entry of data. Reader: no multi-step form asks for the same information twice (re-audit). |
| 4.1.1 Parsing | Supports | Supports | Removed from WCAG 2.2 (always satisfied per the 2.2 errata for 2.0 and 2.1). Listed for VPAT and 2.1 completeness. |
| 4.1.2 Name, Role, Value | Supports | Supports | Staff: the palette and other overlays are dialogs with aria-modal (UI-01, UI-14, UI-28), every icon button is named (UI-13), settings and editor controls are named (UI-04, UI-12), the TipTap editor is a named textbox with a toolbar. Since version 1 (#2336): painted state is exposed (UI-20); tabs follow the APG pattern and disclosures set aria-expanded (UI-31); "New article" is a link, not a button in a link (UI-41); no aria-label on generic elements (UI-47); the empty /assembly slot is a real button (UI-02); comment marks have a role (UI-21); the people roster names the person in its row actions (UI-19). Component tests assert the roles and states; axe passes at serious on every scanned staff route. No screen reader has checked the result. Reader: every field and button has a name and role, checkboxes and radios are grouped, and states are native (accessibility tree for every route). Not yet confirmed with a screen reader. |
Table 2: Success Criteria, Level AA
| Criteria | Staff application | Reader pages | Remarks and explanations |
|---|---|---|---|
| 1.2.4 Captions (Live) | Not Applicable | Not Applicable | No live media. |
| 1.2.5 Audio Description (Prerecorded) | Not Applicable | Not Applicable | No video. |
| 1.3.4 Orientation | Supports | Supports | Nothing locks orientation; the reader routes were checked at 1280 and 390 px wide, the staff app has a 390 px layout. |
| 1.3.5 Identify Input Purpose | Supports | Supports | Staff: sign-in, password reset, two-factor, invite, join and the account profile and security forms set autoComplete (email, current-password, new-password, one-time-code, name); the old registration form is gone (UI-35). Reader: the subscribe form's name and email fields set autoComplete="name" and "email". |
| 1.4.3 Contrast (Minimum) | Supports | Supports | Staff: fixed, by calculation and held by tests: the shared tokens (design-token-contrast.test.ts: --muted-foreground 5.28:1, --destructive, --good, --warn, the destructive tints, the affirmative button, the read-more marker, and since #2365 the empty required-slot label at 5.8:1 in dark), and since #2362 every palette text class in both themes and on hover, composited with its opacity (palette-text-contrast.test.ts, UI-10), and the /audit actor chips, now at least 4.62:1 (UI-09). axe's color-contrast passes at serious on every scanned route. Since version 2, every opacity stacked on a token text color (text-muted-foreground/NN, text-foreground/NN, fill- and stroke-, list markers and placeholders) is found across src/ and composited on the page, card and muted surfaces in both themes, at 4.5:1 for text and 3:1 for large text and icons (UI-08, #2376, non-text-contrast.test.ts). The stacks that measured 2.9 to 3.5:1 were lifted; on this version the nine left were decorative (separators, bullets, row chevrons, an empty-state illustration) or repeated visible text, and #2609 draws them in the solid --muted-foreground, so the check waives none. Reader: passes axe in both schemes on all 46 route states. The Next reader pages are light only; the route-handler pages do not follow prefers-color-scheme. |
| 1.4.4 Resize Text | Not Evaluated | Not Evaluated | No 200% zoom check was run on either scope. The reader routes reflow at 320 px (400% of a 1280 px window), which suggests 1.4.4 holds there, but suggestion is not a result. Target 2027-01-29. |
| 1.4.5 Images of Text | Supports | Supports | Interface text is HTML text in both scopes; logotypes are exempt. Graphics in an edition body are rated in the email ACR. |
| 1.4.10 Reflow | Partially Supports | Supports | Staff: the editor rails become a phone rail below 1024 px, and article types now has a section picker there (UI-22, #2336), so no finding is open. The rating stays below Supports because nothing in the staff app has been measured at 320 px, the width the criterion names, and only /pipeline and the analytics tabs at 390 px; the 390 px pass in 2026-09 is what found UI-22. Reader: 0 px horizontal overflow at 390 and 320 px on every route, including the web copies of the fixture edition (re-audit). |
| 1.4.11 Non-text Contrast | Supports | Supports | Staff: fixed: --ring at 3.49:1 drawn solid, --input borders at 3.22:1 and above, color-scheme declared (UI-07, UI-29, UI-30, #2324, unit-tested); icons drawn in a palette text class are held to 3:1 by palette-text-contrast.test.ts (#2362). Since version 2, icons drawn at an opacity of a token are measured with the text stacks (1.4.3), and every graphic colored outside the text classes that carries meaning (health and status dots, category dots, chart strokes, fills and bands) is in a registry in non-text-contrast.test.ts held to 3:1 on what it is drawn on in both themes, with a guard that fails on any new small round dot not listed (UI-08, #2376; UI-60 readiness words, #2398; UI-61 team analytics bands, #2404). The graphics left as they are are decorative or repeat visible text beside them, each with its reason in the test. Reader: the signup fields' focus ring is solid gray-900, about 17:1 (RD-01, #2331); the other routes use the browser ring or a 3 px #1e3a6e outline, measured in the keyboard walk. |
| 1.4.12 Text Spacing | Not Evaluated | Not Evaluated | Not tested on either scope. Owner step in the re-audit (manual step 3) with a text-spacing bookmarklet; for the staff app, a sample of routes. Target 2027-01-29. |
| 1.4.13 Content on Hover or Focus | Not Evaluated | Not Applicable | Staff: tooltips and hover cards (the /assembly candidate list, strip slots) were not scanned in either audit (coverage gaps). Whether each can be dismissed, hovered and persists is unchecked. Target 2027-03-26. Reader: no hover or focus-triggered content; no dialog, menu or disclosure on any reader page. |
| 2.4.5 Multiple Ways | Supports | Not Evaluated | Staff: pages are reachable from the sidebar, the command palette and /search. Reader: whether an archived edition can be reached two ways (the archive list and the email link, or more) was not assessed. Target 2027-01-29. |
| 2.4.6 Headings and Labels | Supports | Supports | Staff: repeated row controls name their subject (UI-49, #2327); auth cards and /edition-details have an h1 and cards a heading (UI-32, #2336). /articles/[id], the article editor, has an h1 naming the story, and /settings/health no longer skips a level (UI-58, #2375); the strict staff scan holds both. Reader: fixed on every web copy: one hidden h1, the edition's subject (RD-05, #2331, #2337). |
| 2.4.7 Focus Visible | Supports | Supports | Staff: every listed outline-none site, the /submit fields and the TipTap editor have a focus-visible ring at 3:1 (UI-07, #2324); since version 1 the Ready queue and the ideas list move real focus, so the ring is the browser's focus (UI-03, #2336). Reader: a visible focus change at every stop on every route (re-audit), with RD-01 fixed. |
| 2.4.11 Focus Not Obscured (Minimum) (2.2 only) | Not Evaluated | Supports | Staff: sticky headers and drawers were not checked against focused controls. Target 2027-02-26. Reader: every focus stop was inside the viewport (re-audit keyboard walk). |
| 2.5.7 Dragging Movements (2.2 only) | Supports | Not Applicable | Staff: kanban cards have "Move to…" and /assembly has "Place in…" (UI-02, UI-23); social queue, section and block reordering have Move up / Move down (UI-17, #2336). Kanban column resize has, beside the drag and the keyboard splitter (UI-51), Narrower and Wider buttons on each resizable column header (24 px, named with the column) that step the width to the splitter's limits with a single click or tap (UI-59, #2398, kanban-target-size.test.tsx). Reader: no dragging. |
| 2.5.8 Target Size (Minimum) (2.2 only) | Supports | Supports | Staff: card checkbox, assignee trigger, calendar items and strip links are 24 px or more (UI-42 partly); since #2362 the drag grip's target is 24 × 24 and the column splitter's hit area 24 px wide (UI-42, kanban-target-size.test.tsx), and the social queue's Move button is 24 px (#2336). axe target-size passes on every scanned staff route. Reader: reader-question and survey rows are at least 24 px high (RD-13, #2331), and axe target-size passes on every reader route, including the thank-you page and the survey form now in e2e/a11y.spec.ts. |
| 3.1.2 Language of Parts | Partially Supports | Partially Supports | Neither scope can mark a passage in another language: the TipTap editor has no language control, and the reader pages' own text is English only while a web copy carries the newsletter's language (#1724). Not an issue for English-only tenants, which all current tenants are. Spanish pages are a separate umbrella; the decision on a language-of-parts control, or on stating an English-only basis as the email ACR does for 3.1.1, is due 2027-03-26. |
| 3.2.3 Consistent Navigation | Supports | Not Evaluated | Staff: one sidebar from one model (src/components/layout/nav-model.ts) on every signed-in page. Reader: the Next pages and the route-handler pages are built separately, and the re-audit did not compare the order of their repeated links. Target 2027-01-29. |
| 3.2.4 Consistent Identification | Supports | Supports | The same functions keep the same names across pages in both scopes; no finding in either audit. |
| 3.3.3 Error Suggestion | Supports | Supports | Staff: article validators name the field and say what to do ("Add a headline", "Keep the notes to 5,000 characters or fewer"; UI-40, #2327); the forms #2365 wired say which task or field is wrong ("Task 2: …"). Since version 3, the forms #2375 wired (UI-57) say what to do: "Add a name, a key to save this template." (structure-tab.tsx), "Enter the number of recipients as a whole number, or leave it blank." and "Enter the date and time you sent it." (manual-send.tsx), "Give the rule a name" and "Add at least one action" (src/lib/automation/rules.ts; the rule's number fields are clamped, so they never fail), "Enter a full web address, starting https://." and "Delay must be a whole number of days." (newsletter-forms.tsx), the poll card's "Add a question to save this poll." and "Add at least 2 options to save this poll." (src/lib/polls/poll-card.ts), and proof-send names each address it refuses ("Not an address: …") or the count to cut ("That's <n>; remove some."). Reader: the subscribe errors say "Enter your email address." or "Enter a valid email address." in the page (RD-10, #2360). |
| 3.3.4 Error Prevention (Legal, Financial, Data) | Supports | Supports | Staff: template deletion asks for confirmation (UI-25), the one finding against 3.3.4, now closed; deleting a kanban card from either menu opens the same confirmation (#2348). No legal or financial transactions. Reader: unsubscribe and "stay" are two-step (ask, then confirm); the preference centre changes nothing until Save. |
| 3.3.8 Accessible Authentication (Minimum) (2.2 only) | Supports | Not Applicable | Staff: sign-in is email and password with autoComplete for password managers and no paste blocking (no onPaste handler in src/app or src/components), passkeys, and a one-time code with autoComplete="one-time-code". No CAPTCHA or puzzle. Reader: readers never sign in; links are signed tokens. |
| 4.1.3 Status Messages | Supports | Supports | Staff: triage-deck verdicts, upload status, the caption limit and presence changes are announced through live regions (UI-33, UI-34, UI-53, #2327); kanban moves and every Move up / Move down have a polite live region (UI-03, UI-17); Ready-queue and ideas-list selection is now real focus (UI-03, #2336); the subscriber list's load and search errors are alerts (#2365). Since version 3 (UI-57, #2375), the forms #2365 left alone announce their errors: an inline role="alert" (template editor, automation rule dialog, custom web address, manual send, add-idea), a role="status" (poll card, subscriber attributes), an aria-live total (population shares), or the save's toast (newsletter settings forms, issue title, subject and preview). Since version 4 (UI-62, #2630), proof-send's other-addresses check, which shows "Not an address: …" or "That's <n>; remove some." as you type in the help line the field is described by, also speaks it through a visually hidden polite role="status" region (ProofAddressAnnouncer in proof-send.tsx) once the message has held still for 800 ms and only when its text changes; a cleared error empties the region silently (proof-send.test.tsx). Not yet heard with a screen reader (staff pass, 2027-04-02). Reader: outcomes use role="status" (subscribe, manage, stay, preferences); the preferences outcome also leads the title and takes focus (RD-03, #2331); the subscribe error is a role="alert" keyed per attempt, so a repeat is announced again (RD-10, #2360). Not yet heard with a screen reader. |
Legal context
These two paragraphs describe the rules this report is usually read against. They are not legal advice; a covered entity's counsel decides how the rules apply to it.
ADA Title II. The U.S. Department of Justice's rule on the web content
and mobile apps of state and local governments (28 CFR part 35, subpart H,
§§ 35.200–35.205, published 2024-04-24) adopts WCAG 2.1 Level AA as the
technical standard. Under the interim final rule of 2026-04-20 (91 FR 20902,
effective on publication; comments closed 2026-06-22, so the dates could
still change when it is finalized), a public entity with a total population
of 50,000 or more must comply by 2027-04-26; smaller entities and special
district governments by 2028-04-26. The rule applies to web content an
entity provides or makes available, directly or through contractual,
licensing or other arrangements, so content a vendor builds or posts for the
entity is covered. The third-party exception is only for a third party that
is not posting under a contractual, licensing or other arrangement with the
entity (28 CFR 35.201(d)). In that arrangement Pressroom is the vendor and the
newsletter office is the covered entity, and the reader pages (sign-up,
archive, preferences, polls) and the archived editions would ordinarily fall
within the web content the office makes available to the public. The
archived-content exception applies only to content that was created before
the compliance date, is kept only for reference, research or recordkeeping,
is held in an area clearly designated as an archive, and has not been changed
since it was archived. An edition sent after the office's own compliance date
(2027-04-26 or 2028-04-26, by population), or edited after it was archived,
does not qualify. Neither the rule text nor DOJ's ada.gov guidance mentions
email; the email output is rated separately in email-acr.md.
Sources: ada.gov, "Fact Sheet: New Rule on the Accessibility of Web Content
and Mobile Apps Provided by State and Local Governments";
the interim final rule, 91 FR 20902 (2026-04-20);
and the rule text at eCFR, 28 CFR 35.200.
Colorado HB21-1110 (signed 2021-06-30) requires the Office of Information Technology to set accessibility standards for state information technology from the most recent WCAG. A state agency not in full compliance by 2024-07-01 is in violation of the state's laws against disability discrimination and subject to their remedies. It allocates liability between public bodies: "Liability for noncompliance as to content lies with the public entity or state agency that manages the content, whereas noncompliance of the platform hosting the content lies with the public entity or state agency that manages the platform." On Pressroom the office manages its content (articles, images, alt text, the colors it chooses) and Pressroom supplies the platform (templates, reader pages, the staff application) as the office's vendor; what the vendor owes the office is a matter for the contract and the office's counsel, not something this report decides. HB24-1454 (signed 2024-05-24) gave a public body that showed good-faith efforts, posted quarterly progress reports and ran a redress process immunity from liability until 2025-07-01, one year past the 2024-07-01 deadline; that period has ended, so the Colorado deadline has passed. Sources: leg.colorado.gov, HB21-1110 and leg.colorado.gov, HB24-1454.
Known limitations
- Self-authored, and no screen reader has been used on either scope
(see Notes). Owner steps: the reader script by 2026-12-15, a staff pass on
the four formerly critical flows (palette,
/assembly, kanban, settings) and UI-28 by 2027-04-02. Until then a Supports in 2.4.3, 4.1.2 and 4.1.3 rests on the accessibility tree, component tests and the code. - Open pull requests are not counted. The reader and email gate (#2144, PR #2369: strict reader scans, more reader routes in CI, keyboard checks of the reader forms) was open at version 3. It has merged since, but versions 4 and 5 re-rate only the UI-57 and UI-62 rows, so its evidence is not yet counted elsewhere. It adds evidence; it changes no rating here.
- New findings on this version, to be added to the #2138 checklist
(proposed in PR #2372, which publishes this version):
- UI-57 (3.3.1, 3.3.3, 4.1.3): #2365 tied errors to their fields on the forms it lists but left alone every form in a file batch D (#2362) was changing at the time (the media picker, manual send, the template structure tab, newsletter forms, reader host, automation rules, the poll card, the add-idea dialog and others). Closed in version 4 (#2375).
- UI-58 (1.3.1, 2.4.6): the CI scan's moderate findings on
main:/articles/[id], the article editor, has no h1 and a landmark that repeats another's role and name;/settings/healthskips a heading level. Closed in version 3 (#2375). - UI-59 (2.5.7): kanban column resize has a keyboard splitter (UI-51) but no single-pointer alternative to the drag, for example a width setting or wider and narrower buttons. Closed in version 3 (#2398).
- Routes the audits did not reach.
- Staff, never scanned at runtime: the architect-gated
/settings/workflowand/settings/webhooks, and/settings/newsletters/[id]/website(where/settings/linksnow redirects). - Staff, not in
e2e/a11y.spec.ts(scanned only in the 2026-09 pass, if at all, on older code):/calendar,/search,/media,/audit,/discovery,/editions,/editions/[id]/analytics,/ideas/brainstorm,/notificationsand its preferences,/qa/email,/snippets,/setup,/article-preview/[id],/login/two-factor,/two-factor-setup,/onboarding, and every settings page except/settings,/settings/subscribers,/settings/healthand/settings/house-style(among them article types, integrations, users, branding, newsletters, account and security). Fixes on these routes rest on source review and component tests./ideas,/pipelineand/assemblyare also in the scroll-region scan. - Staff states never scanned: empty and error states, validation-error markup, popovers and hover cards, the AI assist bar, the comment thread, the crop editor, drag in progress; one tenant and one data shape only. There has been no browser keyboard walk of the staff app since the 2026-09 audit; key handling since then is tested in components.
- Reader:
error.tsxwas reviewed from source only (it needs a server fault)./u/test,/u/manage,/u/[token]/one-click, the bad-token notices and most?signup=results were audited once but are not in the CI scan (#2144, open PR #2369). Only Chromium was used.
- Staff, never scanned at runtime: the architect-gated
- Not measured: 200% text resize (1.4.4), text spacing (1.4.12), help placement (3.2.6), reader navigation order and multiple ways (3.2.3, 2.4.5), content on hover (1.4.13, staff), focus obscured by sticky content (2.4.11, staff), redundant entry in the staff multi-step flows (3.3.7) and the staff app at 320 px. (Opacity-stacked muted text and icons, and graphics colored outside the text classes, are measured since version 3: UI-08, #2376.)
- Customer content. Alt text, images and the colors an office picks are the office's; the email ACR covers the checks Pressroom runs on them.
- Language. English only in the interface; no language-of-parts control.
Remediation targets
Every row rated below Supports, with what closes it and the target date. All dates are before 2027-04-26. Dates come from the #2138 and #2139 checklists; "evaluate" means a check that decides the rating, not a known defect.
| Criterion | Scope | Rating | Closes it | Target |
|---|---|---|---|---|
| 1.4.10 | Staff | Partially Supports | a 320 px pass on the staff routes (and 390 px beyond /pipeline) | 2027-02-26 |
| 3.1.2 | Both | Partially Supports | owner decision: a language-of-parts control, or a stated English-only basis | 2027-03-26 |
| 3.2.6, 1.4.4, 1.4.12 | Both | Not Evaluated | evaluate | 2027-01-29 |
| 2.4.5, 3.2.3 | Reader | Not Evaluated | evaluate | 2027-01-29 |
| 2.4.11 | Staff | Not Evaluated | evaluate | 2027-02-26 |
| 1.4.13 | Staff | Not Evaluated | evaluate | 2027-03-26 |
| 3.3.7 | Staff | Not Evaluated | evaluate | 2027-03-26 |
Closed since version 1 (rated Supports on this version): staff 1.1.1, 1.4.1, 2.1.1, 2.1.4 (was Does Not Support), 2.2.2, 2.4.1, 2.4.2, 2.4.3, 3.3.2, 4.1.2, 2.4.7 and 2.5.8; reader 1.3.1, 1.3.3, 2.4.1, 3.3.1, 3.3.2 and 2.4.6. Closed since version 2 (rated Supports on version 3): staff 1.3.1, 1.4.3, 1.4.11, 2.4.6 and 2.5.7 (#2609). Closed since version 3 (rated Supports on version 4): staff 3.3.1 and 3.3.3 (UI-57, #2375). Closed since version 4 (rated Supports on version 5): staff 4.1.3 (UI-62, #2630).
Legal disclaimer
This report is self-authored by the Pressroom project. It describes the application as of the version and date above, from the evidence listed under Evaluation methods. It is not a third-party certification, and the Legal context section is a summary of public sources, not legal advice.