Repository navigation
Screen readers still cannot read Experience content after #673 (form, subscription, and form-state cases) #675
Description
Summary
#673 added dialog semantics to the message slideout and bar templates, closing #670.
Three accessibility defects in the same area remain in the build now in production, and
the customer who raised #670 is still reporting unreadable Experiences.
Verified against the build currently served at
https://c.lytics.io/static/pathfora.min.js (v1.2.21, byte-identical to master
dfce6f6, checked 2026-08-26). Behavior confirmed by rendering each widget type and
layout in Chrome and inspecting the resulting DOM, not by reading templates.
Defect 1: form, subscription slideout and subscription bar have no dialog semantics
#673 changed only src/templates/message/. These templates were not covered and still
render with no pf-widget-container, no role, and no accessible name or description:
src/templates/form/slideout.htmlsrc/templates/subscription/slideout.htmlsrc/templates/subscription/bar.html
Measured, before any customer-side workaround:
form/slideout wrap=ROOT | role=NONE | labelledby=notset | describedby=notset
subscription/slideout wrap=ROOT | role=NONE | labelledby=notset | describedby=notset
subscription/bar wrap=ROOT | role=NONE | labelledby=notset | describedby=notset
Customer-visible effect: a lead-capture Experience is not announced as a dialog and its
headline and message are never read.
Defect 2: the aria references in the #673 templates do not resolve
message/slideout.html and message/bar.html carry:
<div class="pf-widget-container" role="dialog"
aria-labelledby="pf-widget-headline"
aria-describedby="pf-widget-message">No element in either template has id="pf-widget-headline" or
id="pf-widget-message" — those strings are present as class names only. Both
references point at ids that do not exist. modal and gate are unaffected because
their templates do set those ids.
Measured on the production build:
message/slideout role=dialog | aria-labelledby="pf-widget-headline" -> DANGLING (no such id)
| aria-describedby="pf-widget-message" -> DANGLING (no such id)
message/bar role=dialog | aria-labelledby="pf-widget-headline" -> DANGLING (no such id)
| aria-describedby="pf-widget-message" -> DANGLING (no such id)
modal role=dialog | aria-labelledby="pf-widget-headline" -> RESOLVES text="<headline>"
Customer-visible effect: the Experience announces as a dialog but has no accessible
name or description, so its text is not read. bar additionally references a headline
element that does not exist in that layout at all.
Defect 3: form success and error states are not exposed after submit
constructFormState (src/rollup/form/construct-form-state.js) creates additional
elements carrying the same pf-widget-headline and pf-widget-message class names, one
set per state. A form Experience with formStates therefore renders three of each.
handleFormStates (src/rollup/form/handle-form-states.js) reveals a state by adding a
success or error class; it does not update any accessible name or description, and
the state containers are not marked as live regions.
Measured on a form slideout with formStates.success configured:
headline elements = 3, message elements = 3
0: "Join our list" parent=pf-widget-content
1: "Thanks!" parent=success-state
2: "Oops" parent=error-state
after the success class is applied:
visible text = "Thanks!"
dialog name = "Join our list" (unchanged)
Customer-visible effect: a screen-reader user submits a lead-capture form and receives
no announcement of the confirmation or of a submission error. This is the point in the
interaction where feedback matters most.
Customer impact (ZD 22915 — Clorox)
- Clorox retested after v1.2.21 shipped. Their "present message" Experiences improved;
their "capture lead" Experiences are still not read out. That maps to Defect 1. - Defect 2 means the Add aria labels to slideout and bar widgets #673 change does not deliver a working accessible name on any
layout it touched, so the improvement Clorox observed came from a customer-side
workaround rather than from the shipped templates. - Clorox is a public-facing consumer brand treating this as a compliance requirement,
and lead-capture forms are the Experience type where a missed submission has the most
direct business consequence. - The library is a single shared script loaded by every customer running Experiences, so
all three defects are present on every customer site using the affected types.
Legal / compliance exposure
- US web accessibility is enforced under the ADA (Title III), with WCAG 2.1/2.2 Level AA
as the de facto conformance standard, and Section 508 in federal contexts. - The EU European Accessibility Act (in force June 2025) creates comparable obligations
for global brands. - Unnamed dialogs, unresolvable
aria-labelledbyreferences, and unannounced form
status changes are all commonly cited WCAG failures (name/role/value; status
messages). Because this markup is injected into the customer's own page, it becomes
part of the customer's compliance surface.
References
- Experience popups are not accessible to screen readers (WCAG/ADA compliance gap) #670 — original report (closed by Add aria labels to slideout and bar widgets #673)
- Add aria labels to slideout and bar widgets #673 — added dialog semantics to
messageslideout and bar - Fix aria-labelledby typo on dialog widget containers #669 — corrected an invalid label attribute on the modal/gate containers
- Zendesk 22915 (Clorox)
Verification notes
Defects 1 and 2 were measured by rendering each type and layout against the production
build. Defect 3 was measured by rendering a form slideout with formStates and applying
the state class that handleFormStates applies. DOM and attribute state was inspected
directly; announcement behavior in a specific screen reader was not tested.
Activity
sean-cstk commentedon Sep 4, 2026
Tracked in Jira: LYT-1120 — https://contentstack.atlassian.net/browse/LYT-1120
Filed on the LYT board per the escalation path for work that needs a core engineer. The Jira ticket carries the same detail and is the system of record for this work.
LYT-1120: announce form success and error states
Add a widget playground for manual testing and demos
ashyablok-cs commentedon Sep 21, 2026
closed by #675