-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Apply user updates for mobile navigation accessibility #31401
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Apply user updates for mobile navigation accessibility #31401
Conversation
…moving unnecessary comments and simplifying focus handling logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
6 file(s) reviewed, 6 comment(s)
Edit PR Review Bot Settings | Greptile
code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/MobileNavigation.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/useFocusTrap.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/useFocusTrap.tsx
Outdated
Show resolved
Hide resolved
View your CI Pipeline Execution ↗ for commit c6daf4e.
☁️ Nx Cloud last updated this comment at |
…aria-controls in MobileNavigation
@MichaelArestad Do you have any input here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yatishgoel Nice!
@ndelangen These changes seem great. I am not an expert on aria attributes and I have not implemented anything like useFocusTrap
though I understand the reasoning.
I believe this breaks a few Interaction tests in Navigation that were targeting elements with a specific title
attribute. We shouldn't be using title
attributes for this anyway. title
attributes are not designed to be used for anything other than iframes.
Regarding the title
attributes, they were being used as tooltips, which isn't great. In the near future, I do think we should probably:
- Create new tooltips that are accessible, specifically the tooltips designed to show a short string (black background, white text).
- Implement those tooltips in almost every situation where we use
title
.
@ndelangen Can you code review this when you get a chance? Thank you! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks so much for undertaking this work, @yatishgoel! This is hard work so please don't take anything in my review as a criticism of your effort. I very much appreciate you giving this a go!
You applied a dialog
role
with an aria-modal
attribute. That's great, and it's what I wrote in the issue so really this is my own fault! It's unfortunately missing a powerful element of the Dialog element: showModal
. The showModal
function lets you instruct the browser to open a modal and install a focus trap for you, which greatly reduces the amount of code to write and makes better use of standards.
You also used the navigation
role
in your code. It would be preferrable to use the nav
element directly instead. Generally speaking (and as reminded on https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/navigation_role), it's preferable to use the HTML standard element rather than its inferred role and attributes.
I shouldn't have mentioned role
in my issue. I sometimes refer to roles instead of elements out of habit because I don't know if the HTML markup is controlled and can be edited, but when a role can be fulfilled through the use of an element, it should. That allows for better future compatibility and easier maintenance.
To move forward, I suggest removing the focus trap implementation and using showModal
instead, and switching to actual nav/dialog elements. Then, there would only be minor details left to address.
code/core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/useFocusTrap.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/useFocusTrap.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/useFocusTrap.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/useFocusTrap.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/useFocusTrap.tsx
Outdated
Show resolved
Hide resolved
…ate management. Updated MobileAddonsDrawer and MobileMenuDrawer to use dialog elements for better focus control. Removed unused useFocusTrap hook. Simplified MainContentMatcher by removing unnecessary props. Enhanced MobileNavigation to manage addon panel state more effectively.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A small bug left to fix and a refactor could be made to regroup the modal hooks into a single file, but this is great overall and would definitely fix the linked issue. Kudos, @yatishgoel!
code/core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx
Outdated
Show resolved
Hide resolved
…ialog hook for improved dialog management. Introduced useModalDialog for better encapsulation of dialog logic and enhanced accessibility. Updated shortcut handling to skip events when a dialog is open.
export const MobileAddonsDrawer: FC<MobileAddonsDrawerProps> = ({ | ||
children, | ||
id, | ||
isOpen, | ||
onClose, | ||
}) => { | ||
const dialogRef = useModalDialog({ isOpen, onClose }); | ||
|
||
return ( | ||
<Container ref={dialogRef} id={id} aria-label="Addon panel"> | ||
{children} | ||
</Container> | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yatishgoel also, the Close button does not work on the addon panel.
code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
Outdated
Show resolved
Hide resolved
code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
Outdated
Show resolved
Hide resolved
…ling - Introduced `forceCloseDialog` function in MobileMenuDrawer to encapsulate dialog closing logic. - Updated onExited callback to use `forceCloseDialog` for cleaner code. - Enhanced useModalDialog to handle Escape key for closing the dialog and prevent default behavior. - Removed redundant dialog close logic from useModalDialog to streamline the component's functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Congrats on fixing the animations! Can you please test the mobile addon panel again? I see a few remaining issues:
- It's positioned in the middle of the screen instead of the bottom
- The close button doesn't close the panel
- It seems I have to press Esc 2-3 times to close the panel
- Fix MobileMenuDrawer and MobileAddonsDrawer appearing centered instead of bottom - Add full width positioning for mobile dialogs - Fix Esc key requiring double press in addon drawer - Fix close button not working properly - Ensure smooth exit animations with proper timing coordination - Override browser default modal positioning with &[open] selector
Thanks for the feedback! I actually just fixed those exact issues in both MobileAddonsDrawer.tsx and MobileMenuDrawer.tsx: Positioning: Added Close Behavior: Converted MobileAddonsDrawer to use React Transition with the same working pattern as MobileMenuDrawer - added Both mobile drawers now use identical patterns: React Transition + useModalDialog + forceCloseDialog for behavior, and the same CSS positioning overrides. MobileMenuDrawer was working correctly, so I used it as the reference to fix MobileAddonsDrawer. Both should now appear at bottom with full width and proper close behavior. |
Package BenchmarksCommit: The following packages have significant changes to their size or dependencies:
|
Before | After | Difference | |
---|---|---|---|
Dependency count | 49 | 49 | 0 |
Self size | 31.85 MB | 31.87 MB | 🚨 +18 KB 🚨 |
Dependency size | 17.41 MB | 17.41 MB | 0 B |
Bundle Size Analyzer | Link | Link |
sb
Before | After | Difference | |
---|---|---|---|
Dependency count | 50 | 50 | 0 |
Self size | 1 KB | 1 KB | 0 B |
Dependency size | 49.26 MB | 49.28 MB | 🚨 +18 KB 🚨 |
Bundle Size Analyzer | Link | Link |
@storybook/cli
Before | After | Difference | |
---|---|---|---|
Dependency count | 216 | 216 | 0 |
Self size | 582 KB | 582 KB | 0 B |
Dependency size | 94.57 MB | 94.59 MB | 🚨 +18 KB 🚨 |
Bundle Size Analyzer | Link | Link |
@storybook/codemod
Before | After | Difference | |
---|---|---|---|
Dependency count | 185 | 185 | 0 |
Self size | 31 KB | 31 KB | 0 B |
Dependency size | 78.71 MB | 78.73 MB | 🚨 +18 KB 🚨 |
Bundle Size Analyzer | Link | Link |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code does everything I'd like it to do! Now this is just a matter of getting the CI passing.
We can now turn our attention to the CI :) I haven't looked in detail at the CI reports, but if you get stuck, feel free to ask me to take over and I will have a look. It seems there are a few tests that need to be updated, maybe you could start with this? https://app.circleci.com/jobs/github/storybookjs/storybook/843273
Closes #31380
What I did
This PR significantly enhances the accessibility of the mobile navigation and addresses focus management issues, resolving the core concerns raised in #31380. It also incorporates the DOM order fix for desktop and mobile reading consistency from #31076.
Key improvements:
ARIA Attributes for Mobile Navigation:
aria-label
,aria-expanded
, andaria-controls
to properly communicate its state and relationship with the menu drawer (MobileNavigation.tsx
).aria-label
andaria-expanded
.Accessible Mobile Menu Drawer (
MobileMenuDrawer.tsx
):role="dialog"
,aria-modal="true"
, and anaria-label
for clear anouncement to screen reader users.role="navigation"
.Focus Management and Trapping:
useFocusTrap
hook has been implemented and applied toMobileMenuDrawer.tsx
.Tab
andShift+Tab
, and closing via theEscape
key.aria-hidden="true"
andtabIndex="-1"
when the mobile menu is open to prevent interaction with background content (Layout.tsx
).DOM Order for Reading Consistency (Addresses Fix Storybook accessibility order #31076):
Layout.tsx
ensures<SidebarContainer>
renders before the main content (<MainContentMatcher>
) for a logical reading order.<MobileNavigation>
trigger component is rendered first in the DOM within its mobile layout block, while CSSorder
is used for its visual placement at the bottom. This ensures screen readers encounter the navigation trigger in a logical sequence.General Code Refinements:
useFocusTrap
.useFocusTrap
.id
props andaria-controls
for theMobileAddonsDrawer
as well, preparing it for similar focus trap implementation if it contains interactive elements.Checklist for Contributors
Testing
The changes in this PR are covered in the following automated tests:
Manual testing
This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!
This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!
yarn task --task sandbox --start-from auto --template react-vite/default-ts
Tab
andShift+Tab
. Ensure focus stays within the menu.Escape
. Verify the menu closes and focus returns to the "Open navigation menu" button.aria-hidden="true"
) when the menu was open.Documentation
MIGRATION.MD
Checklist for Maintainers
When this PR is ready for testing, make sure to add
ci:normal
,ci:merged
orci:daily
GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found incode/lib/cli-storybook/src/sandbox-templates.ts
Make sure this PR contains one of the labels below:
Available labels
bug
: Internal changes that fixes incorrect behavior.maintenance
: User-facing maintenance tasks.dependencies
: Upgrading (sometimes downgrading) dependencies.build
: Internal-facing build tooling & test updates. Will not show up in release changelog.cleanup
: Minor cleanup style change. Will not show up in release changelog.documentation
: Documentation only changes. Will not show up in release changelog.feature request
: Introducing a new feature.BREAKING CHANGE
: Changes that break compatibility in some way with current major version.other
: Changes that don't fit in the above categories.🦋 Canary release
This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the
@storybookjs/core
team here.core team members can create a canary release here or locally with
gh workflow run --repo storybookjs/storybook canary-release-pr.yml --field pr=<PR_NUMBER>
Greptile Summary
Here's a concise summary of the key accessibility improvements made to the mobile navigation components:
Enhanced mobile navigation components with comprehensive accessibility features and proper DOM ordering.
role="dialog"
,aria-modal
,aria-controls
,aria-expanded
) inMobileNavigation.tsx
andMobileMenuDrawer.tsx
useFocusTrap
hook for modal dialogsLayout.tsx
to ensure sidebar renders before main content for logical screen reader flowaria-hidden
andtabIndex
controls to main content when mobile menu is openThe changes significantly improve screen reader compatibility and keyboard navigation while maintaining visual layout through CSS ordering rather than DOM manipulation.