Skip to content

Conversation

@rebeccaballantyne
Copy link

@rebeccaballantyne rebeccaballantyne commented May 2, 2018

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
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
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
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?

Copy link
Author

@rebeccaballantyne rebeccaballantyne May 3, 2018

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
Member

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

Copy link
Contributor

@chang47 chang47 left a comment

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
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
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
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
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
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
Author

Choose a reason for hiding this comment

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

Good idea!

"bundlesize": [
{
"path": "../apps/test-bundle-button/dist/test-bundle-button.min.js",
"maxSize": "47.6 kB"
Copy link
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