Skip to content

Fixes focus issue for contextual menus#4744

Merged
joschect merged 17 commits into
microsoft:masterfrom
rebeccaballantyne:rebeba/contextual-menu-focus
May 7, 2018
Merged

Fixes focus issue for contextual menus#4744
joschect merged 17 commits into
microsoft:masterfrom
rebeccaballantyne:rebeba/contextual-menu-focus

Conversation

@rebeccaballantyne

@rebeccaballantyne rebeccaballantyne commented May 2, 2018

Copy link
Copy Markdown

Pull request checklist

Description 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.

onMenuClick(ev, this);
}

const menuProps = this.props.menuProps;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should do:

const menuProps = {
    ...this.props.menuProps,
    shouldFocusOnContainer: true
};

Avoid modifying existing props objects.


if (!ev.defaultPrevented) {
const menuProps = this.props.menuProps;
if (menuProps) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same comment regarding using ... to mix in a new prop.

>
<div
role='menu'
role={ shouldFocusOnContainer ? 'menu' : undefined }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why should the role change based on whether or not it is focusable? What gets labeled as a menu in the other case?

@rebeccaballantyne rebeccaballantyne May 3, 2018

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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?

@betrue-final-final betrue-final-final self-assigned this May 3, 2018
@betrue-final-final

Copy link
Copy Markdown
Contributor

This works great. Tested in Narrator on Edge and with a mouse.

@chang47 chang47 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Adding some comments

handleTabKey={ FocusZoneTabbableElements.all }
>
<ul
role='presentation'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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 }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For my understanding, this is the part of the code where we prevent focus being added to the container for the contextual menu?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes.

this._onSubMenuDismiss(ev);
} else { // This has a collapsed sub menu. Expand it.
this.setState({
expandedByMouseClick: (ev.nativeEvent.detail !== 0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since we added a comment in BaseButton regarding why we're using:

ev.nativeEvent.detail

Let's put it here too.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good idea!

Comment thread scripts/package.json Outdated
"bundlesize": [
{
"path": "../apps/test-bundle-button/dist/test-bundle-button.min.js",
"maxSize": "47.6 kB"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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

@joschect
joschect merged commit 8b36d24 into microsoft:master May 7, 2018
Markionium added a commit to Markionium/office-ui-fabric-react that referenced this pull request May 13, 2018
* 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)
  ...
@microsoft microsoft locked as resolved and limited conversation to collaborators Aug 31, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When opening a contextual menu, first menu item does not receive focus

7 participants