Skip to content

fix(a11y): announce dynamic status and errors via live regions (A11Y-… - #3005

Open
sunilsabatp wants to merge 3 commits into
developfrom
fix/a11y-010-status-messages
Open

fix(a11y): announce dynamic status and errors via live regions (A11Y-…#3005
sunilsabatp wants to merge 3 commits into
developfrom
fix/a11y-010-status-messages

Conversation

@sunilsabatp

@sunilsabatp sunilsabatp commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Addresses A11Y-010: Dynamic status, errors, and results not announced (missing live regions) by introducing a reusable LiveRegion component and applying it across the application.

Previously, dynamic updates such as errors, validation messages, filter result counts, loading states, and success messages were rendered as ordinary content, so screen readers did not announce them automatically.

Changes

  • Added a reusable LiveRegion component for announcing dynamic content.
  • Used politeness="assertive" (role="alert") for validation errors, error popups, and failed actions.
  • Used politeness="polite" (role="status") for filter result counts, empty states, upload progress, success messages, and other non-urgent updates.
  • Added visually hidden live regions and aria-busy to loading indicators where appropriate.
  • Kept live regions mounted where possible so updates are announced reliably when their content changes.
  • Preserved the existing UI and styling by supporting different rendered elements via the as prop.
  • Updated both desktop and mobile project list controls to announce filter result changes.
  • Marked the completed accessibility finding in ACCESSIBILITY_FINDINGS.md.

Accessibility Impact

This change addresses:

  • WCAG 4.1.3 – Status Messages (Level AA)
  • WCAG 3.3.1 – Error Identification (Level A)

Screen reader users will now receive announcements for:

  • Validation and error messages
  • Upload and save status
  • Filter result counts
  • Empty states
  • Loading progress
  • Success messages

without requiring focus to move.

Testing

Manual

  • Trigger validation errors and verify they are announced.
  • Perform uploads and verify success and failure messages are announced.
  • Apply project filters and verify updated result counts and empty states are announced.
  • Verify loading indicators correctly expose the busy state.

Screen Reader

  • Verify error messages interrupt current speech.
  • Verify non-urgent status messages are announced without moving focus.
  • Verify announcements occur when dynamic content changes.

Regression

  • Verify there are no visual UI changes.
  • Verify existing layouts and styling remain unchanged.
  • Verify all affected flows continue to function as expected.

@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
planet-webapp-multi-tenancy-setup Ready Ready Preview Jul 27, 2026 10:24am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PR adds a reusable LiveRegion component and applies it to loading, error, validation, filtering, submission, and transaction states. Busy indicators and visually hidden announcements are added, while accessibility documentation records completed findings and a new follow-up item.

Changes

Accessibility announcements

Layer / File(s) Summary
LiveRegion foundation
src/features/common/LiveRegion/*
Adds configurable live-region semantics, politeness handling, ARIA attributes, and visually hidden styling.
Common and project announcements
src/features/common/ContentLoaders/..., src/features/common/Layout/..., src/features/common/RedeemCode/..., src/features/projectsV2/...
Adds announcements for loading, errors, redeem failures, empty project results, and filter counts.
User workflow announcements
src/features/user/BulkCodes/..., src/features/user/CompleteSignup/..., src/features/user/DonationReceipt/..., src/features/user/PlanetCash/...
Adds live announcements for upload, issuance, signup validation, donor contact states, and transaction loading, including aria-busy updates.
Accessibility documentation updates
docs/accessibility/ACCESSIBILITY_FINDINGS.md, docs/accessibility/FOLLOW_UPS.md
Updates completed-finding status and adds the FU-006 empty-state illustration follow-up.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: mohitb35

Poem

A rabbit hears the regions speak,
Of loading states and errors meek.
Counts and warnings now appear,
Busy signals ring out clear.
Docs mark progress, fresh and bright—
Accessibility hops tonight! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding live regions for dynamic accessibility announcements.
Description check ✅ Passed The description is mostly complete and covers summary, changes, accessibility impact, and testing, with only minor template omissions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/a11y-010-status-messages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/accessibility/ACCESSIBILITY_FINDINGS.md`:
- Around line 1555-1563: Update the accessibility findings summary to include
A11Y-010 in the completed findings list and change the reported completion count
from 14 to 15, while preserving the existing completed-item formatting.

In `@src/features/common/ContentLoaders/Projects/GlobeLoader.tsx`:
- Around line 13-14: Move the LiveRegion component outside the root motion.div
marked aria-busy="true" in GlobeLoader, or limit aria-busy to only the visual
loader, while preserving the existing loading announcement and globe rendering
behavior.

In `@src/features/common/LiveRegion/index.tsx`:
- Around line 48-49: Update the LiveRegion consumer in UploadWidget so its
live-region nodes remain mounted rather than being remounted via key={status}.
Maintain persistent regions for each politeness level and update their content
as status changes, preserving the documented accessibility contract.

In `@src/features/common/LiveRegion/LiveRegion.module.scss`:
- Line 12: In the visually hidden styling for LiveRegion, replace the deprecated
clip declaration with clip-path using an inset(50%) value, preserving the
existing hidden-element behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2d2388f1-4fb4-4568-9f32-44531cdcd559

📥 Commits

Reviewing files that changed from the base of the PR and between acb64f6 and dc8ca58.

⛔ Files ignored due to path filters (3)
  • public/static/locales/en/common.json is excluded by !**/*.json
  • public/static/locales/en/donationReceipt.json is excluded by !**/*.json
  • public/static/locales/en/me.json is excluded by !**/*.json
📒 Files selected for processing (14)
  • docs/accessibility/ACCESSIBILITY_FINDINGS.md
  • src/features/common/ContentLoaders/Projects/GlobeLoader.tsx
  • src/features/common/Layout/ErrorPopup/index.tsx
  • src/features/common/LiveRegion/LiveRegion.module.scss
  • src/features/common/LiveRegion/index.tsx
  • src/features/common/RedeemCode/RedeemFailed.tsx
  • src/features/projectsV2/ProjectList/index.tsx
  • src/features/projectsV2/ProjectListControls/ProjectListControlForMobile.tsx
  • src/features/projectsV2/ProjectListControls/index.tsx
  • src/features/user/BulkCodes/components/UploadWidget.tsx
  • src/features/user/BulkCodes/forms/IssueCodesForm.tsx
  • src/features/user/CompleteSignup/components/SignupToggles.tsx
  • src/features/user/DonationReceipt/microComponents/DonorContactForm.tsx
  • src/features/user/PlanetCash/screens/Transactions.tsx

Comment thread docs/accessibility/ACCESSIBILITY_FINDINGS.md Outdated
Comment thread src/features/common/ContentLoaders/Projects/GlobeLoader.tsx Outdated
Comment on lines +48 to +49
* Keep the live region mounted and update its content instead of mounting a
* new one, as this is more reliably announced by assistive technologies.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep live-region nodes mounted in consumers.

The documented contract conflicts with src/features/user/BulkCodes/components/UploadWidget.tsx:118-152, which remounts LiveRegion with key={status}. Newly inserted role="status" nodes are not reliably announced across assistive technologies; keep persistent regions per politeness and update their content instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/common/LiveRegion/index.tsx` around lines 48 - 49, Update the
LiveRegion consumer in UploadWidget so its live-region nodes remain mounted
rather than being remounted via key={status}. Maintain persistent regions for
each politeness level and update their content as status changes, preserving the
documented accessibility contract.

padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file =="
if [ -f src/features/common/LiveRegion/LiveRegion.module.scss ]; then
  cat -n src/features/common/LiveRegion/LiveRegion.module.scss
else
  fd -a 'LiveRegion\.module\.scss' .
fi

echo
echo "== stylelint/package configs =="
for f in .stylelintrc .stylelintrc.json .stylelintrc.js .stylelintrc.cjs package.json; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    sed -n '1,220p' "$f"
  fi
done

echo
echo "== searches for deprecated clip / clip-path / visually hidden =="
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' 'clip\s*:|clip-path|visually hidden|sr-only|sr-only' . | head -200

echo
echo "== browser support markers =="
for f in .browserslistrc brio .browserslist browserlistrc browserlistrc.json; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    cat "$f"
  fi
done

Repository: Plant-for-the-Planet-org/planet-webapp

Length of output: 8253


Replace deprecated clip with clip-path.

clip: rect(...) is legacy CSS; for this visually hidden pattern, use clip-path: inset(50%) so the project stops relying on deprecated CSS when browser support is already modern enough for the rest of the codebase.

🧰 Tools
🪛 Stylelint (17.14.0)

[error] 12-12: Deprecated property "clip" (property-no-deprecated)

(property-no-deprecated)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/common/LiveRegion/LiveRegion.module.scss` at line 12, In the
visually hidden styling for LiveRegion, replace the deprecated clip declaration
with clip-path using an inset(50%) value, preserving the existing hidden-element
behavior.

Source: Linters/SAST tools

…(A11Y-010)

- Render each polite LiveRegion as a persistent, visually hidden region outside
  the branch it used to live in, and revert the visible message to plain markup.
  A role="status" region inserted together with its text is often not announced,
  while a text change inside an already-observed region is
- Leave the visible elements conditional. They sit in flex containers with a gap,
  so always rendering them would add spacing. The hidden region is absolutely
  positioned and out of flow, so layout is unchanged

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/features/user/BulkCodes/forms/IssueCodesForm.tsx (1)

384-384: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Apply aria-busy to the container that contains all workflow controls.

This <form> contains only the submit button; inputs, totals, and errors are outside it. Put aria-busy={isProcessing} on StyledFormContainer (or make it the actual form) so the complete issuing workflow is marked busy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/user/BulkCodes/forms/IssueCodesForm.tsx` at line 384, Move
aria-busy={isProcessing} from the form in IssueCodesForm to StyledFormContainer,
which contains the inputs, totals, errors, and submit control; alternatively
make StyledFormContainer the form while preserving the existing submission
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/features/user/BulkCodes/forms/IssueCodesForm.tsx`:
- Line 384: Move aria-busy={isProcessing} from the form in IssueCodesForm to
StyledFormContainer, which contains the inputs, totals, errors, and submit
control; alternatively make StyledFormContainer the form while preserving the
existing submission behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 035f244d-2cf5-4093-8bad-d8fa60955781

📥 Commits

Reviewing files that changed from the base of the PR and between dc8ca58 and 1ae6274.

📒 Files selected for processing (11)
  • docs/accessibility/ACCESSIBILITY_FINDINGS.md
  • docs/accessibility/FOLLOW_UPS.md
  • src/features/common/ContentLoaders/Projects/GlobeLoader.tsx
  • src/features/common/LiveRegion/index.tsx
  • src/features/projectsV2/ProjectList/index.tsx
  • src/features/projectsV2/ProjectListControls/ProjectListControlForMobile.tsx
  • src/features/projectsV2/ProjectListControls/index.tsx
  • src/features/user/BulkCodes/components/UploadWidget.tsx
  • src/features/user/BulkCodes/forms/IssueCodesForm.tsx
  • src/features/user/DonationReceipt/microComponents/DonorContactForm.tsx
  • src/features/user/PlanetCash/screens/Transactions.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/features/user/PlanetCash/screens/Transactions.tsx
  • src/features/projectsV2/ProjectListControls/ProjectListControlForMobile.tsx
  • docs/accessibility/ACCESSIBILITY_FINDINGS.md
  • src/features/user/DonationReceipt/microComponents/DonorContactForm.tsx
  • src/features/common/ContentLoaders/Projects/GlobeLoader.tsx
  • src/features/common/LiveRegion/index.tsx
  • src/features/user/BulkCodes/components/UploadWidget.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant