fix: a11y follow up fixes#3634
Merged
Merged
Conversation
Contributor
SDK Size
|
szuperaz
approved these changes
Jun 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🎯 Goal
Follow up
a11ypass on top of #3632. Covers the message row, the attachment thumbnail gallery, the full screen image/video gallery overlay, the reactions UI, the message cell annotations and date separators, the channel preview date, and the poll option row. VoiceOver and TalkBack now read each surface with proper labels, units and focus behavior and the gallery traps focus while open.🛠 Implementation details
Pressablenow announces "Message from {sender}" / "Message from you". Messages with interactive children (poll, quoted message, attachments, shared location) opt out of being a single focus stop so VO/TalkBack can drill into the children; an iOS-only absolute-fillViewcarries the sender label so the speaker is still announced when focus lands inside the inner content.hasInteractiveAccessibilityContentoverride - new field onAccessibilityConfigthat receives the SDK's baseline boolean and lets integrators extend the "is this message interactive?" decision without losing the defaults. Resolved upstream inuseCreateMessageContextand exposed as a stable boolean onMessageContext.MessageTextContainerand thePollheader now setaccessible accessibilityRole='text'so TalkBack auto-composes the descendant<Text>content. Conditional onhasInteractiveAccessibilityContentfor the message text to avoid double-announce on plain messages.Pressablenow carries ana11y/Gallery Imageora11y/Gallery Videolabel (added across all 13 locales), explicitrole='button', and the existinga11y/Double tap to openhint. Announces as "Gallery video, button. Double tap to open."accessibilityViewIsModalon theImageGalleryroot and theMessageOverlayHostLayerhost on iOS. Android gets a newOverlayA11yShieldsibling wrapper that flipsimportantForAccessibility='no-hide-descendants'when either the gallery or the message context menu is active.role='adjustable',value={ text: 'N of M' }, increment/decrement actions, and anaccessibilityLabelof "Image Gallery". Swipe up/down cycles through assets.requesterNodefield.Gallery.tsxcaptures the thumbnail's node handle viafindNodeHandleand passes it throughopenImageGallery; on unmount the gallery restores focus viaAccessibilityInfo.setAccessibilityFocusinside an rAF.ReactionListItemgainsrole='button'(trips the Android compose gate so TalkBack reads the emoji's CLDR name instead of the reactiontypestring) andstate.selected.ReactionButtondrops a brokenaccessibilityLabelKeythat was literally untranslated across every locale.MessageRepliesPressablenow hasrole='button', anaccessibilityLabelreading the reply count ("1 Reply" / "N Replies"), and anaccessibilityHintof "Double tap to view thread" (new i18n key across all 13 locales). Participant avatars in the indicator are hidden from thea11y tree so they no longer announce one-by-one.
SentToChannelHeader("Replied to a thread · View") andMessageReminderHeader("Reminder set · 5 minutes left") are now marked decorative so focus moves directly from the label to the action.getDateStringForA11yhelper that substitutesLLfor the calendarsameElseslot, preserving locale relative words like "Today" / "Yesterday". Wired intoInlineDateSeparator(announces"April 8, 2026") and
ChannelPreviewStatus(announces "10:30 AM" for same-day messages via asameDay: 'LT'override). TalkBack honors the override too, no platform branching needed.Texton each poll option row now carries anaccessibilityLabelusing the existing{{count}} votesplural key. Announces "0 votes" / "1 vote" / "N votes" instead of just the bare number.New shared components and exports
OverlayA11yShield(package/src/components/Accessibility/) - Android-only focus-trap shield. Subscribes to the overlay context and the message-overlay store to computeisAnyOverlayActive, then wraps{children}in aViewthat flipsimportantForAccessibility='no-hide-descendants'andaccessibilityElementsHiddenwhile an overlay is active. On iOS it's a pure passthrough selected at module load.getDateStringForA11y(package/src/utils/i18n/getDateString.ts) - sibling helper togetDateString. Produces a TTS-friendly calendar string by substitutingLLfor thesameElseslot in the locale's calendar formats, with an optionalcalendarFormatOverridesparameter for callers whose visible formatdiverges from the locale defaults.
AccessibilityConfig.hasInteractiveAccessibilityContent- new override hook for integrators (see above).MessageContext.hasInteractiveAccessibilityContent- new stable boolean field consumed byMessageContentandMessageTextContainer.ImageGalleryState.requesterNodeand the matchingopenImageGallery({ requesterNode? })argument.🎨 UI Changes
iOS
Android
🧪 Testing
☑️ Checklist
developbranch