Skip to content
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

fix!(container-menu): improves logic for returning focus to trigger #659

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

ze-flo
Copy link
Contributor

@ze-flo ze-flo commented Aug 30, 2024

Description

Improve the logic for returning focus to trigger. Adds optional restoreFocus prop to manager focus return to trigger.

💥 BREAKING CHANGE:

A new restoreFocus prop has been added. By default restoreFocus is true and will return the focus to the trigger on menu item selection, ESC / TAB key press, and clicking outside the menu dropdown. User who need to keep the dropdown open on selection must set restoreFocus={false} and manually handle the focus return.

Detail

  • Returning focus to trigger is now executed synchronously before calling the onChange callback. Now, when a menu item triggers Garden's Modal open, the focus will automatically be restored to the menu trigger after the modal has closed.
Screen.Recording.2024-08-29.at.10.19.34.AM.mov

Checklist

  • 🌐 demo is up-to-date (npm start)
  • 💂‍♂️ includes new unit tests
  • ♿ tested for WCAG 2.1 AA compliance
  • 📝 tested in Chrome, Firefox, Safari, and Edge

@ze-flo ze-flo requested a review from a team as a code owner August 30, 2024 20:39
@coveralls
Copy link

coveralls commented Aug 30, 2024

Coverage Status

coverage: 95.711% (-0.005%) from 95.716%
when pulling d7a27c0 on ze-flo/menu-focus-fix
into ec77a9d on main.

geotrev
geotrev previously approved these changes Sep 4, 2024
Copy link
Contributor

@geotrev geotrev left a comment

Choose a reason for hiding this comment

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

I like this approach. To reiterate what we discussed, we agreed that deferring trigger focus didn't make sense as consumers can't (and shouldn't) control this behavior anyway. It also leaves room for folks to refocus another element in response to menu closing without affecting screen reader announcements.

packages/menu/src/useMenu.ts Show resolved Hide resolved
Copy link
Contributor

@geotrev geotrev left a comment

Choose a reason for hiding this comment

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

Quick status comment:

Flo and I met offline to go over the current approach and how we can maybe improve focus behavior between controlled and uncontrolled instances of isExpanded. Currently, this PR will only synchronously focus the button if isExpanded is uncontrolled.

Instead, we think there could be an opportunity here to give more direct trigger focus control through the use of a new parameter, which would also slightly change how Menu works in controlled scenarios by requiring consumers to focus their buttons when isExpanded is false.

To-be-discussed at tomorrow's meeting of the minds to get team consensus. 🧐

@@ -272,22 +278,32 @@ export const useMenu = <T extends HTMLElement = HTMLElement, M extends HTMLEleme
event.stopPropagation();

const changeType = StateChangeTypes.TriggerClick;
const nextIsExpanded = !controlledIsExpanded;
Copy link
Contributor

Choose a reason for hiding this comment

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

I actually think the code below reads better if we use !controlledIsExpanded. I confused nextisExpanded as referring to the next / nested menu state.

packages/menu/src/useMenu.ts Show resolved Hide resolved
@geotrev geotrev dismissed their stale review September 11, 2024 22:07

awaiting consensus on new direction

@ze-flo ze-flo changed the title fix(container-menu): improves logic for returning focus to trigger fix!(container-menu): improves logic for returning focus to trigger Sep 13, 2024
Copy link
Contributor

@geotrev geotrev left a comment

Choose a reason for hiding this comment

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

I love how well the new direction cleaned up with the code!

MenuContainer.defaultProps = {
defaultExpanded: false,
restoreFocus: true,
rtl: false
Copy link
Contributor

@geotrev geotrev Sep 16, 2024

Choose a reason for hiding this comment

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

[nit] IIRC it would be acceptable to leave defaultExpanded and rtl as undefined since they should be read as falsey anyway.

@@ -66,6 +66,8 @@ export interface IUseMenuProps<T = HTMLButtonElement, M = HTMLElement> {
focusedValue?: string | null;
/** Determines focused value on menu initialization */
defaultFocusedValue?: string;
/** Returns focus to the trigger when the menu is collapsed */
Copy link
Contributor

Choose a reason for hiding this comment

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

[nit] Maybe this can align with our description on the modal container prop:

Returns keyboard focus to the element that triggered the modal

if (item.href) {
if (key === KEYS.SPACE) {
event.preventDefault();
event.preventDefault();
Copy link
Contributor

Choose a reason for hiding this comment

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

Glad this worked wtih anchors. For some reason I thought it wouldn't.

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

Successfully merging this pull request may close these issues.

5 participants