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

[Transition] Fix hidden children appearing in a11y tree #14465

Merged
merged 7 commits into from
Feb 15, 2019

Conversation

eps1lon
Copy link
Member

@eps1lon eps1lon commented Feb 8, 2019

  • make element requirement in transitions explicit (we always used cloneElement so that was always implicated)
  • set aria-hidden and visibility: hidden if exited => children are not part of the a11y tree and not focusible

I observed that the code variant switches in our docs were still focusable. This is due to Fade simply setting opacity to 0 which has not effect on the a11y tree.

Videos taken in chrome 72

production:
mui-focus-fade-old

PR:
mui-focus-fade-new

Behavior verified in latest chrome, firefox, edge and IE 11 (safari is not working in browserstack).

By setting the hidden html prop they should automatically disappear but this will set display: none by spec. However by setting display: initial the children are focusable again. Only by setting visibility: hidden do we achieve that we keep the previous layout behavior and remove the content from the a11y tree.
Sets the aria-hidden property for screenscreaders and sets visibility to hidden to remove the childs from the tab order.

Nice side effect: In Concurrent React the hidden attribute will cause React to render the content with lower priority. We can't use hidden because that will cause display: none. This was the original implementation but display: initial is not supported in IE 11

Also removed some redundant prop type validation for children and marked it as required similar to #14444

Going to add this to the other transitions. Would close #12632

@eps1lon eps1lon force-pushed the docs/a11y-code-variant-switch branch from 5704135 to d7ea6b7 Compare February 8, 2019 14:19
@eps1lon eps1lon changed the title Docs/a11y code variant switch [Fade] Fix child appearing in the a11y tree if faded out Feb 8, 2019
@eps1lon eps1lon requested a review from mbrookes February 8, 2019 14:25
@eps1lon eps1lon added the accessibility a11y label Feb 8, 2019
@eps1lon eps1lon force-pushed the docs/a11y-code-variant-switch branch from d7ea6b7 to 63e91ac Compare February 8, 2019 15:35
@eps1lon eps1lon changed the title [Fade] Fix child appearing in the a11y tree if faded out [core] Fix child components appearing in a11y if they're not "in" Feb 8, 2019
@eps1lon eps1lon changed the title [core] Fix child components appearing in a11y if they're not "in" [core] Fix children appearing in a11y tree if they're not "in" Feb 8, 2019
Copy link
Member Author

@eps1lon eps1lon left a comment

Choose a reason for hiding this comment

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

Failing test are IMO expected. If you don't want to mount if in={false} then react-transition-group provides mountOnEnter={false}

@oliviertassinari oliviertassinari added the component: transitions This is the name of the generic UI component, not the React module! label Feb 8, 2019
@oliviertassinari oliviertassinari changed the title [core] Fix children appearing in a11y tree if they're not "in" [Transition] Fix children appearing in a11y tree if they're not "in" Feb 8, 2019
@oliviertassinari
Copy link
Member

oliviertassinari commented Feb 10, 2019

We have a problem with the focus logic. A visibility hidden element can't receive the focus. Now, the problem is that our Modal, Dialog, Menu components don't wait for the transition to start to focus the children, hence it's not working. The Firefox 52 test fail is just a symptom, you could see that the dialog autofocus logic was broken too on Chrome latest. There is no quick win here, it's a difficult problem to solve. I think that we can think of a solution handle:

@oliviertassinari oliviertassinari force-pushed the docs/a11y-code-variant-switch branch from 05c6913 to 2618e1e Compare February 10, 2019 11:02
@eps1lon
Copy link
Member Author

eps1lon commented Feb 10, 2019

We have a problem with the focus logic. A visibility hidden element can't receive the focus. Now, the problem is that our Modal, Dialog, Menu components don't wait for the transition to start to focus the children, hence it's not working. There is no quick win here, it's a difficult problem to solve.

I think the issue is that those components set the in prop to true while simultaneously using an imperative focus in the DOM. They would need to wait for the changes to be commited to the DOM and then focus i.e. set the prop in the render phase and then focus in e.g. useEffect. Currently we set the prop and focus during render which is causing the issue.

The good thing is that this was always an issue that might've caused some subtle bugs. The bad thing is that we also need to fix dependent components.

@eps1lon
Copy link
Member Author

eps1lon commented Feb 13, 2019

github UI is broken for this PR. It shows 41 commits and 600 files changed while compare correctly shows only 23 commits and 12 files changed. Going to squash it. History is saved locally.

Squashed commit of the following:

commit 491239f60e7cf1769ef159ee447df9001fe63f46
Merge: bf011ce aad72ed
Author: Sebastian Silbermann <[email protected]>
Date:   Wed Feb 13 10:29:31 2019 +0100

    Merge branch 'next' into docs/a11y-code-variant-switch

commit bf011ce
Author: Sebastian Silbermann <[email protected]>
Date:   Tue Feb 12 21:13:26 2019 +0100

    [Collapse] Don't consider hidden if collapsedHeight > 0

commit 59ee3e5
Author: Sebastian Silbermann <[email protected]>
Date:   Tue Feb 12 21:07:36 2019 +0100

    [Collapse] Fix css hidden property name

commit 32dd6ff
Merge: a2d6e83 2618e1e
Author: Sebastian Silbermann <[email protected]>
Date:   Tue Feb 12 21:03:44 2019 +0100

    Merge branch 'docs/a11y-code-variant-switch' of github.com:eps1lon/material-ui into docs/a11y-code-variant-switch

commit a2d6e83
Author: Sebastian Silbermann <[email protected]>
Date:   Sat Feb 9 11:03:56 2019 +0100

    [core] Normalize transitions child style implementation

commit 8d16305
Author: Sebastian Silbermann <[email protected]>
Date:   Sat Feb 9 09:05:49 2019 +0100

    fixup

commit ae08e11
Author: Sebastian Silbermann <[email protected]>
Date:   Sat Feb 9 09:05:34 2019 +0100

    fixup

commit 7b2cae2
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 20:27:43 2019 +0100

    [Slide] Fix tests

commit 9cdb582
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 20:19:01 2019 +0100

    [core] Normalize transitions API

commit 752cde5
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 16:31:28 2019 +0100

    [Fade] Fix display none on IE 11

commit d10309b
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 14:22:31 2019 +0100

    [Fade] Fix propTypes not warning on missing child element

commit 1ed6682
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 14:21:44 2019 +0100

    [Fade] Fix child element appearing in the a11y tree if hidden visually

commit 6cbaabe
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 14:17:39 2019 +0100

    [Fade] Test a11y for invisible content

commit 2618e1e
Author: Olivier Tassinari <[email protected]>
Date:   Sun Feb 10 10:49:22 2019 +0100

    change class name

commit ef1e87a
Author: Olivier Tassinari <[email protected]>
Date:   Sun Feb 10 01:55:34 2019 +0100

    look into the build fail

commit af3d812
Author: Sebastian Silbermann <[email protected]>
Date:   Sat Feb 9 11:03:56 2019 +0100

    [core] Normalize transitions child style implementation

commit 5082f2f
Author: Sebastian Silbermann <[email protected]>
Date:   Sat Feb 9 09:05:49 2019 +0100

    fixup

commit 32699b1
Author: Sebastian Silbermann <[email protected]>
Date:   Sat Feb 9 09:05:34 2019 +0100

    fixup

commit 459b8f8
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 20:27:43 2019 +0100

    [Slide] Fix tests

commit 5dba229
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 20:19:01 2019 +0100

    [core] Normalize transitions API

commit 63e91ac
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 16:31:28 2019 +0100

    [Fade] Fix display none on IE 11

commit fb70b73
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 14:22:31 2019 +0100

    [Fade] Fix propTypes not warning on missing child element

commit 85d75ce
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 14:21:44 2019 +0100

    [Fade] Fix child element appearing in the a11y tree if hidden visually

commit 658b4d3
Author: Sebastian Silbermann <[email protected]>
Date:   Fri Feb 8 14:17:39 2019 +0100

    [Fade] Test a11y for invisible content
@eps1lon eps1lon force-pushed the docs/a11y-code-variant-switch branch from bf011ce to 61a6d0d Compare February 13, 2019 09:38
@eps1lon eps1lon changed the title [Transition] Fix children appearing in a11y tree if they're not "in" [Transition] Fix hidden children appearing in a11y tree Feb 13, 2019
@eps1lon
Copy link
Member Author

eps1lon commented Feb 13, 2019

Quick update regarding FF 52 focus issue: It does work properly in browserstack and fiddling with https://deploy-preview-14465--material-ui.netlify.com/demos/menus/#simple-menu.

I suspect in the test the menu is still hidden. Other browsers can focus that content while FF cannot.

@oliviertassinari
Copy link
Member

@eps1lon It's not related to Firefox, it's broken for everybody: #14465 (comment).

@eps1lon
Copy link
Member Author

eps1lon commented Feb 13, 2019

@eps1lon It's not related to Firefox

I was speaking about the build failure. What do you mean?

I did not understand that comment:

A visibility hidden element can't receive the focus.

This is intended. This is the purpose of this PR: Hidden elements should not be focusable.

Now, the problem is that our Modal, Dialog, Menu components don't wait for the transition to start to focus the children, hence it's not working.

They don't transition into aria-hidden=false. It's not hidden as soon as the in=true.

Could you explain what is currently not working? Elements seem to receive focus just fine when manually testing keyboard focus on https://deploy-preview-14465--material-ui.netlify.com/demos/menus/#simple-menu

@oliviertassinari
Copy link
Member

feb-13-2019 12-13-16

@eps1lon
Copy link
Member Author

eps1lon commented Feb 13, 2019

@oliviertassinari What browser?

Debug notes (limited to Menu.test.js should focus the first item as nothing has been selected:

console.log(document.querySelector('[data-mui-test="Popover"]')) after wrapper.setState({ open: true });:
ChromeHeadless:

<div
  class="MuiPaper-root-7 MuiMenu-paper-1 MuiPaper-elevation8-17 MuiPaper-rounded-8 MuiPopover-paper-2"
  data-mui-test="Popover"
  aria-hidden="false"
  role="document"
  tabindex="-1"
  style="opacity: 1; transform: scale(1, 1); transition: opacity 0ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, transform 0ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; top: 16px; left: 16px; transform-origin: -8px -8px;"
>
  <ul
    class="MuiList-root-34 MuiList-padding-35"
    role="menu"
    data-mui-test="Menu"
  >
    <li
      class="MuiButtonBase-root-53 MuiListItem-root-41 MuiListItem-default-44 MuiListItem-gutters-49 MuiListItem-button-50 MuiMenuItem-root-38 MuiMenuItem-gutters-39"
      tabindex="0"
      role="menuitem"
    >
      Menu Item 1<span class="MuiTouchRipple-root-56" />
    </li>
    <li
      class="MuiButtonBase-root-53 MuiListItem-root-41 MuiListItem-default-44 MuiListItem-gutters-49 MuiListItem-button-50 MuiMenuItem-root-38 MuiMenuItem-gutters-39"
      tabindex="-1"
      role="menuitem"
    >
      Menu Item 2<span class="MuiTouchRipple-root-56" />
    </li>
    <li
      class="MuiButtonBase-root-53 MuiListItem-root-41 MuiListItem-default-44 MuiListItem-gutters-49 MuiListItem-button-50 MuiMenuItem-root-38 MuiMenuItem-gutters-39"
      tabindex="-1"
      role="menuitem"
    >
      Menu Item 3<span class="MuiTouchRipple-root-56" />
    </li>
  </ul>
</div>;

Firefox 52:

<div
  class="MuiPaper-root-7 MuiMenu-paper-1 MuiPaper-elevation8-17 MuiPaper-rounded-8 MuiPopover-paper-2"
  data-mui-test="Popover"
  aria-hidden="false"
  style="opacity: 1; transform: scale(1, 1); transition: opacity 0ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, transform 0ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; top: 16px; left: 16px; transform-origin: -8px -8px 0px;"
  role="document"
  tabindex="-1"
>
  <ul
    class="MuiList-root-34 MuiList-padding-35"
    role="menu"
    data-mui-test="Menu"
  >
    <li
      class="MuiButtonBase-root-53 MuiListItem-root-41 MuiListItem-default-44 MuiListItem-gutters-49 MuiListItem-button-50 MuiMenuItem-root-38 MuiMenuItem-gutters-39"
      tabindex="0"
      role="menuitem"
    >
      Menu Item 1<span class="MuiTouchRipple-root-56" />
    </li>
    <li
      class="MuiButtonBase-root-53 MuiListItem-root-41 MuiListItem-default-44 MuiListItem-gutters-49 MuiListItem-button-50 MuiMenuItem-root-38 MuiMenuItem-gutters-39"
      tabindex="-1"
      role="menuitem"
    >
      Menu Item 2<span class="MuiTouchRipple-root-56" />
    </li>
    <li
      class="MuiButtonBase-root-53 MuiListItem-root-41 MuiListItem-default-44 MuiListItem-gutters-49 MuiListItem-button-50 MuiMenuItem-root-38 MuiMenuItem-gutters-39"
      tabindex="-1"
      role="menuitem"
    >
      Menu Item 3<span class="MuiTouchRipple-root-56" />
    </li>
  </ul>
</div>;

only diff at the possition of the inline style attribute.

However Firefox has the element with the className MuiPaper-root-7 MuiMenu-paper-1 MuiPaper-elevation8-17 MuiPaper-rounded-8 MuiPopover-paper-2 in document.activeElement.

Caused by  focus() call race condition: dialog -> item in chrome
but item -> dialog in firefox
@eps1lon eps1lon added the on hold There is a blocker, we need to wait label Feb 13, 2019
@eps1lon
Copy link
Member Author

eps1lon commented Feb 13, 2019

Firefox issue is resolved. Investigating why opening a Dialog does not set focus on the dialog. It was working for Menu which was shown in the resolved firefox issue.

@eps1lon
Copy link
Member Author

eps1lon commented Feb 13, 2019

The issue was that the visibility was hidden for one render cycle in which we changed to in prop from false to true. This causes the modal to handle focus but react-transition-group#Transition will have one cycle where the state is still exited. After that it will switch to entering.

3887ae4 added additional logic to handle this case. aria-hidden is not needed anymore. I originally thought this was enough but aria-hidden does not affect how focus in child elements is handled. Only display and visibility can affect child elements.

@oliviertassinari Could you verify if the issue you reported still exists?

@eps1lon eps1lon removed the on hold There is a blocker, we need to wait label Feb 13, 2019
@oliviertassinari oliviertassinari self-assigned this Feb 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accessibility a11y component: transitions This is the name of the generic UI component, not the React module!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Accordion] Make follow accessibly standards
3 participants