fix(accessibility): ensure screen reader announcements update consistently#1973
fix(accessibility): ensure screen reader announcements update consistently#1973cyphercodes wants to merge 2 commits intoclauderic:masterfrom
Conversation
…ently The useAnnouncement hook was not reliably updating screen reader announcements when dragging sortable items. This was because React batches state updates, causing consecutive identical announcements to be skipped by assistive technologies. The fix clears the announcement before setting the new value, using requestAnimationFrame to ensure the DOM update is flushed between the clear and the new announcement. This creates a detectable change that screen readers will announce. Fixes clauderic#1952
🦋 Changeset detectedLatest commit: 614e8c2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
clauderic
left a comment
There was a problem hiding this comment.
Summary
This PR fixes an issue where screen readers don't re-announce identical text content. It uses a clear-then-set pattern via requestAnimationFrame to force the screen reader to detect the change.
Feedback
Blocking issues
-
Missing changeset:
packages/accessibility/src/hooks/useAnnouncement.tsis a source file in a published package, so a changeset entry is required. Please add a.changeset/*.mdfile listing@dnd-kit/accessibilitywith apatchbump. -
Base branch: This PR targets
master(the legacy branch), notmain(the active development branch). Please double-check which branch you intended to target. If this is intentional for the legacy package, that's fine — just worth confirming.
Suggestions
-
packages/accessibility/src/hooks/useAnnouncement.ts— TherequestAnimationFramecallback isn't cancelled if the component unmounts before the frame fires. While React 18 makes this a no-op (no warning), a cleaner pattern would be to return a cancel handle. For example:const announce = useCallback((value: string | undefined) => { if (value != null) { setAnnouncement(''); const rafId = requestAnimationFrame(() => { setAnnouncement(value); }); return () => cancelAnimationFrame(rafId); } }, []);
This is a suggestion, not a blocker — the current approach will work correctly in React 18+.
Changeset
- Status: missing. A changeset is required for changes to
packages/*/src/.
Overall
Great fix for a subtle screen reader issue — the clear-then-rAF pattern is the right approach here. Thanks for contributing! Once the changeset is added, this looks good to go.
[claude-review]
|
Thanks for the review. I pushed
I left the PR targeting |
Fixes #1952 - The useAnnouncement hook now clears the announcement before setting the new value, using requestAnimationFrame to ensure screen readers detect the change.