fix: add role="group" to stack layout div with aria-label for WCAG 2.2 compliance - #18
Conversation
….2 compliance The div rendered by stack-layout uses aria-label without an explicit role. Per ARIA 1.2, aria-label is a prohibited attribute on elements with the implicit role="generic" (the default for a div), which is a WCAG 2.2 Level A (4.1.2 Name, Role, Value) violation flagged by an external audit on the kohlerqa account. role="region" makes the element a valid landmark that accepts an accessible name.
|
Hi! I'm VTEX IO CI/CD Bot and I'll be helping you to publish your app! 🤖 Please select which version do you want to release:
And then you just need to merge your PR when you are ready! There is no need to create a release commit/tag.
|
|
Beep boop 🤖 I noticed you didn't make any changes at the
In order to keep track, I'll create an issue if you decide now is not a good time
|
|
Suggestion: use
Since this is a global app (used by every store, not just kohlerqa), this side effect regresses accessibility across the whole installed base just to resolve one account's audit.
Alternative (or complement): make |
role="region" is a landmark and would turn every stack container into a region in the screen-reader landmark navigation, with a generic/duplicated accessible name. role="group" also accepts aria-label and resolves the ARIA 1.2 / WCAG 4.1.2 violation without introducing any landmark, matching the existing pattern in slider-layout. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Change:
|
| Metric | region (before) |
group (after) |
|---|---|---|
role="region" landmarks |
4 (all "Section row") |
0 |
Div with valid aria-label |
4 | 4 |
| ARIA 1.2 violation (label without role) | 0 | 0 |
Note: stack-layout is not placed on any page of this test store, so the live measurement was done on flex-layout (same one-line change, same mechanism). The behavior is identical.
Workspaces to test (axe / screen reader / landmarks rotor)
- Before (
region): https://roleregion--storecomponents.myvtex.com/ - After (
group): https://rolegroup--storecomponents.myvtex.com/
|
Your PR has been merged! App is being published. 🚀 After the publishing process has been completed (check #vtex-io-releases) and doing A/B tests with the new version, you can deploy your release by running:
After that your app will be updated on all accounts. For more information on the deployment process check the docs. 📖 |
…#424) ## What does this PR do? Adds `role="group"` to the `<div>` elements in `ProductSummaryImage` and `ProductSummaryName` that already carry `aria-label`, fixing an accessibility violation identified in an external audit on the kohler account. ## Why is this needed? Both components render a `<div>` with `aria-label` but no explicit `role`. Per the ARIA 1.2 spec, `aria-label` is a **prohibited attribute** on elements with the implicit `role="generic"` (the default for a `<div>`). This violates: - **WCAG 2.2 Level A** — Criterion 4.1.2 (Name, Role, Value) - **ARIA 1.2** — `aria-label` prohibited on generic role elements Reported in Slack ([thread](https://vtex.slack.com/archives/C07CM75TN21/p1785435389561719?thread_ts=1785435386.188349&cid=C07CM75TN21)) / Jira [STR-1158](https://vtex-dev.atlassian.net/browse/STR-1158). The `aria-label` on `ProductSummaryImage` was originally added in #402. ## Why `role="group"` and not `role="region"` or `role="img"`? - `role="region"` is a **landmark**, meant for a small number of significant page sections. Every product summary rendering an image/name container as a landmark would pollute screen-reader landmark navigation. - `role="img"` would collapse the container's descendants (discount badge, collection badges, product name) out of the accessibility tree, hiding information that should remain exposed. - `role="group"` accepts `aria-label`, resolves the ARIA 1.2 / WCAG 4.1.2 violation, introduces no landmark, and keeps descendants exposed to assistive tech. This mirrors the fix applied to the sibling component `vtex.stack-layout` in [vtex-apps/stack-layout#18](vtex-apps/stack-layout#18), which uses the same reasoning to choose `role="group"` over `role="region"`. ## What changed? - `react/ProductSummaryImage.tsx` — set `role="group"` on the image container div - `react/ProductSummaryName.tsx` — set `role="group"` on the name container div - `CHANGELOG.md` — added entry for this fix ## Testing / impact This does not change the visual output, but it does change the accessibility tree: both divs now expose a valid `group` role with their accessible name, and no landmark is introduced. ## References - [ARIA 1.2 — Prohibited aria-* attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-label) - [WCAG 2.2 — 4.1.2 Name, Role, Value](https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html) [STR-1158]: https://vtex-dev.atlassian.net/browse/STR-1158?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
What does this PR do?
Adds
role="group"to the stack layout<div>that already carriesaria-label, fixing the accessibility violation identified in the external audit for the kohlerqa account.Why is this needed?
The current implementation uses
aria-labelon a<div>without an explicitrole. Per the ARIA 1.2 spec,aria-labelis a prohibited attribute on elements with the implicitrole="generic"(the default for<div>).This violates:
aria-labelprohibited on generic role elementsWhy
role="group"and notrole="region"?role="region"is a landmark, meant for a small number of significant page sections. A layout container that always renders anaria-label(falling back to a generic message) would add landmarks with generic/duplicated names, polluting screen-reader landmark navigation.role="group"also acceptsaria-label, resolves the ARIA 1.2 / WCAG 4.1.2 violation, and is not a landmark — so it fixes the audit finding without the side effect. This also keeps stack-layout consistent with the sibling fix invtex.flex-layoutand with the existingrole="group"usage invtex.slider-layout.What changed?
react/index.tsx— setrole="group"on the main stack layout divCHANGELOG.md— added entry for this fixTesting / impact
This does not change the visual output, but it does change the accessibility tree: the div now exposes a valid
grouprole with its accessible name, and no landmark is introduced.References