Fixes focus issue for contextual menus#4744
Conversation
| onMenuClick(ev, this); | ||
| } | ||
|
|
||
| const menuProps = this.props.menuProps; |
There was a problem hiding this comment.
Should do:
const menuProps = {
...this.props.menuProps,
shouldFocusOnContainer: true
};Avoid modifying existing props objects.
|
|
||
| if (!ev.defaultPrevented) { | ||
| const menuProps = this.props.menuProps; | ||
| if (menuProps) { |
There was a problem hiding this comment.
Same comment regarding using ... to mix in a new prop.
| > | ||
| <div | ||
| role='menu' | ||
| role={ shouldFocusOnContainer ? 'menu' : undefined } |
There was a problem hiding this comment.
Why should the role change based on whether or not it is focusable? What gets labeled as a menu in the other case?
There was a problem hiding this comment.
So when focus is NOT on the container (and is instead on the first menu item), adding role='menu' to the container stopped Narrator from reading the aria-label on the menu. Role='group' was fine but so was no role at all for narration behavior. Currently nothing gets labeled as a menu in the case where focus is on the first menu item (and narration works optimally). Is it a big accessibility no-no to not have role='menu' somewhere on a menu?
|
This works great. Tested in Narrator on Edge and with a mouse. |
| handleTabKey={ FocusZoneTabbableElements.all } | ||
| > | ||
| <ul | ||
| role='presentation' |
There was a problem hiding this comment.
Why are we getting rid of the role?
At the very least shouldn't it be something like:
role = { shouldFocusOnContainer ? 'presentation' : undefined }
to match with your changes above.
There was a problem hiding this comment.
This role='presentation' was useless and it's presence didn't impact screen reader behavior at all.
| id={ id } | ||
| className={ this._classNames.container } | ||
| tabIndex={ 0 } | ||
| tabIndex={ shouldFocusOnContainer ? 0 : undefined } |
There was a problem hiding this comment.
For my understanding, this is the part of the code where we prevent focus being added to the container for the contextual menu?
| this._onSubMenuDismiss(ev); | ||
| } else { // This has a collapsed sub menu. Expand it. | ||
| this.setState({ | ||
| expandedByMouseClick: (ev.nativeEvent.detail !== 0) |
There was a problem hiding this comment.
Since we added a comment in BaseButton regarding why we're using:
ev.nativeEvent.detail
Let's put it here too.
| "bundlesize": [ | ||
| { | ||
| "path": "../apps/test-bundle-button/dist/test-bundle-button.min.js", | ||
| "maxSize": "47.6 kB" |
There was a problem hiding this comment.
Worth noting that the current size in the most up to date version of master is 49.6 so this is not a bump of 2KB
* master: (52 commits) Marqueeselection style update (microsoft#4803) Applying package updates. FocusZone: Add the ability to stop focus from propagating outside the FocusZone (microsoft#4823) Unknown persona coin (microsoft#4809) Applying package updates. BaseButton: Allow Alt + Down on menu buttons to open the menu (microsoft#4807) Applying package updates. Website: Scroll to top of page on navigation (microsoft#4810) Applying package updates. ActivityItem: fix getstyles (microsoft#4802) Mark Slider#ValuePosition enum as deprecated as it is unused. (microsoft#4799) Icon: ensure `styles` still works. (microsoft#4805) Popup: Added check for onBlur to prevent focus setting focus to be incorrectly disabled when closing a menu in Chrome (microsoft#4804) Update package.json Move <Layer> to use React portals when available (microsoft#4724) Fix breadcrumb rendering issue when overflow item is at last index (microsoft#4787) Fixes focus issue for contextual menus (microsoft#4744) Remove redundant selected items prop on BaseExtendedPicker (microsoft#4769) SearchBox: New prop for turning off icon animation (microsoft#4794) Add functions to ContextualMenuItem to open and close menus on command (microsoft#4741) ...
Pull request checklist
$ npm run changeDescription of changes
Prior to fix, when a contextual menu was opened, focus always went to the contextual menu container.
The correct behavior (determined via discussion with Jeremy Spurlin/ Ben Truelove/ Chris Schlechty/ Jon Schectman/ Thomas Michon) is as follows:
If user activates contextual menu via keyboarding (pressing enter on a button for example), focus should go to the first focusable menu item.
If user activates contextual menu via mouse click, focus should go to the contextual menu container.
The following is a summary of changes to each file:
BaseButton.tsx: Pipes through to ContextualMenu via new param (shouldFocusOnContainer) how the menu was opened. Right now we disregard user input for "shouldFocusOnContainer" if contextual menu is created via menu params to button. I think that is actually desired behavior as it means we will enforce accessibility. Tweaked _isValidMenuOpenKey so that way "Enter" is considered the valid menu open key for non split button items. This means that on enter key press, _onMenuKeyDown will be executed instead of _onMenuClick.
ContextualMenu.tsx: Responds to new param shouldFocusOnContainer, setting roles and tab indexes appropriately. Note that aria label is read regardless of if focus is put on container or first menu item. Added state expandedByMouseClick so that way the same focus behavior applies to sub-menus.
Focus areas to test
With Narrator on and off (in Edge), test contextual menus, activating via keyboard or via click. Observe different focus behaviors.