[IRN-6372] [BpkBottomSheet] - aria title read on Android TalkBack#4198
[IRN-6372] [BpkBottomSheet] - aria title read on Android TalkBack#4198Stephen Hailey (steviehailey-skyscanner) wants to merge 5 commits intomainfrom
Conversation
…nouncement When BpkBottomSheet has no visible title but has ariaLabel, the navigation bar's aria-labelledby was pointing to an empty element. This caused screen readers (particularly Android TalkBack) to fail to announce the navigation context when focusing on the close button. This fix adds a visually hidden h2 element containing the ariaLabel text, which the navigation bar's aria-labelledby now references when no visible title is present. Co-Authored-By: Claude Opus 4.5 <[email protected]>
|
Visit https://backpack.github.io/storybook-prs/4198 to see this build running in a browser. |
Keep title as empty string rather than null to ensure nav's aria-labelledby points to a different element than the hidden title span, avoiding duplicate reading of ariaLabel. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Match PR element order - place visually hidden h2 after the NavigationBar to prevent screen reader announcing it before the nav context. Co-Authored-By: Claude Opus 4.5 <[email protected]>
|
Visit https://backpack.github.io/storybook-prs/4198 to see this build running in a browser. |
| ).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('renders a hidden h2 with ariaLabel text when no title is provided', () => { |
There was a problem hiding this comment.
Added by Opus - seem comprehensive to me and follow the patterns of surrounding tests ✅
| } | ||
| /> | ||
| {/* Visually hidden title required for Android TalkBack to announce ariaLabel on BottomSheet open when no visible title provided */} | ||
| {showHiddenTitle && ( |
There was a problem hiding this comment.
Same heading level as NavBar normally uses for visual Bottom Sheet title (when it has one)
Tested on Android with TalkBack via "No Header" story and now we do get the aria title announced on open while still maintaining focus on the close button. ✅
| <header className={getClassName('bpk-bottom-sheet--header-wrapper')}> | ||
| <BpkNavigationBar | ||
| id={headingId} | ||
| id={showHiddenTitle ? hiddenTitleId : headingId} |
There was a problem hiding this comment.
Since we adding a Screen Reader heading below using headingId we don't want to pass the same id to Nav Bar and risk a duplicated element id inside with the same id so use an alternative in this case.
|
|
||
| const headingId = `bpk-bottom-sheet-heading-${id}`; | ||
| const hiddenTitleId = `bpk-bottom-sheet-title-hidden-${id}`; | ||
| const showHiddenTitle = !title && 'ariaLabel' in ariaProps; |
There was a problem hiding this comment.
Detect if we're in the situation where we only have a heading for ScreenReader purposes to describe the dialog (no visual title)
There was a problem hiding this comment.
would it be better to use const showHiddenTitle = !title && !!ariaProps.ariaLabel; to exclude the case that ariaLabel is ""?
There was a problem hiding this comment.
Yeah, I think handling empty string is nice - especially when when our variable means we can change it in a single place and benefit from it each place we use it. The types insist that we still check for existence of the property before asserting it but that's fine.
e.g. will change to !title && 'ariaLabel' in ariaProps && ariaProps.ariaLabel
There was a problem hiding this comment.
Pull request overview
This PR fixes an accessibility issue where Android TalkBack fails to announce the bottom sheet context when no visible title is present but an ariaLabel is provided. The solution adds a visually hidden heading element that screen readers can reference.
Changes:
- Add visually hidden h2 element containing ariaLabel text when no visible title exists
- Update navigation bar's aria-labelledby to reference the hidden title when appropriate
- Add comprehensive test coverage for the new hidden title behavior
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| BpkBottomSheet.tsx | Implements visually hidden title logic and imports BpkVisuallyHidden component |
| BpkBottomSheet-test.tsx | Adds test cases for hidden title rendering and ariaLabelledby behavior |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <BpkVisuallyHidden as="h2"> | ||
| <span id={hiddenTitleId}>{ariaProps.ariaLabel}</span> |
There was a problem hiding this comment.
The h2 element is redundant here. Since BpkVisuallyHidden is already rendering as an h2, wrapping a span with the id inside creates an unnecessary DOM nesting. The id should be placed directly on the h2 element instead. Change to: <BpkVisuallyHidden as=\"h2\" id={hiddenTitleId}>{ariaProps.ariaLabel}</BpkVisuallyHidden>
| <BpkVisuallyHidden as="h2"> | |
| <span id={hiddenTitleId}>{ariaProps.ariaLabel}</span> | |
| <BpkVisuallyHidden as="h2" id={hiddenTitleId}> | |
| {ariaProps.ariaLabel} |
There was a problem hiding this comment.
Hey, I added the span because the visually hidden component has no id prop. I agree it could be handy for other scenarios based on it's use here.
- are you suggesting I add one to it as part of this PR?
There was a problem hiding this comment.
Ha just noticed this is from Copilot 😄
|
Visit https://backpack.github.io/storybook-prs/4198 to see this build running in a browser. |
https://skyscanner.atlassian.net/browse/IRN-6372
fix(bottom-sheet): Add visually hidden title for screen reader nav announcement
When BpkBottomSheet has no visible title but has ariaLabel, the navigation bar's aria-labelledby was pointing to an empty element. This caused screen readers (particularly Android TalkBack) to fail to announce the navigation context when focusing on the close button.
This fix adds a visually hidden h2 element containing the ariaLabel text, which the navigation bar's aria-labelledby now references when no visible title is present.
Tested on physical Android device with TalkBack and now announces what the dialog is about based on aria-label. 🎉
Remember to include the following changes:
[Clover-123][BpkButton] Updating the colourREADME.md(If you have created a new component)README.md