Description
When using the temporary variant drawer and opening it, the browser warns:
Blocked aria-hidden on an element because its descendant retained focus. The focus must not be hidden from assistive technology users. Avoid using aria-hidden on a focused element or its ancestor. Consider using the inert attribute instead, which will also prevent focus. For more details, see the aria-hidden section of the WAI-ARIA specification at https://w3c.github.io/aria/#aria-hidden.
Element with focus: <button.MuiButtonBase-root MuiIconButton-root MuiIconButton-edgeEnd MuiIconButton-sizeMedium MuiIconButton-root MuiButtonBase-root css-5ki7wftn>
Ancestor with aria-hidden: <div#root> <div id="root" aria-hidden="true">…</div>
Reason
Unexpected aria-hidden
Based on my diagnosis, SUID incorrectly adds aria-hidden to the div used for mounting MuiModal.
<body style="overflow: hidden">
<div id="root" aria-hidden="true">...</div>
+ <div aria-hidden="true">
<div
class="MuiModal-root MuiDrawer-root MuiDrawer-modal MuiDrawer-root MuiModal-root css-o6o9lwg9"
role="presentation"
>
<div
aria-hidden="true"
class="MuiBackdrop-root MuiModal-backdrop MuiBackdrop-root css-bh4oe82h"
style="opacity: 1; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1)"
></div>
<div
class="MuiPaper-root MuiPaper-elevation MuiPaper-elevation16 MuiDrawer-paper MuiDrawer-paperAnchorRight MuiDrawer-paper MuiPaper-root css-cslrtd3y_1"
style="transform: none; transition: transform 225ms cubic-bezier(0, 0, 0.2, 1)"
>
...
</div>
</div>
</div>
</body>
After reviewing the code, I found the issue originates here:
|
ariaHidden(modal.ref, false); |
|
|
|
const hiddenSiblings = getHiddenSiblings(container); |
|
ariaHiddenSiblings(container, modal.ref, hiddenSiblings, true); |
SolidJS's Portal nests a div when passing modal.ref to the body instead of direct attachment. This causes the ariaHiddenSiblings function to consistently fail to exclude the current drawer element.
A similar issue exists here:
|
ariaHidden(modal.ref, true); |
|
|
|
ariaHiddenSiblings( |
|
containerInfo.container, |
|
modal.ref, |
|
containerInfo.hiddenSiblings, |
|
false |
|
); |
|
this.containers.splice(containerIndex, 1); |
|
} else { |
|
// Otherwise make sure the next top modal is visible to a screen reader. |
|
const nextTop = containerInfo.modals[containerInfo.modals.length - 1]; |
|
// as soon as a modal is adding its modalRef is undefined. it can't set |
|
// aria-hidden because the dom element doesn't exist either |
|
// when modal was unmounted before modalRef gets null |
|
|
|
ariaHidden(nextTop.ref, false); |
|
} |
However, replacing these model.ref with modal.ref.parentElement! still fails to resolve the error.
Unmanaged Focus
Further diagnosis reveals that SUID fails to handle focus management:
Mui Site:
> document.activeElement
<body dir="ltr" class="mode-light">…</body>
> document.querySelector('header .MuiIconButton-root').click()
undefined
> document.activeElement
<div class="MuiPaper-root MuiPaper-elevation MuiPaper-elevation16 MuiDrawer-paper MuiDrawer-paperAnchorLeft css-iqol3p" tabindex="-1" style="--Paper-shadow: var(--muidocs-shadows-16); --Paper-overlay: var(--muidocs-overlays-16); transform: none; transition: transform 225ms cubic-bezier(0, 0, 0.2, 1);">…</div>flex
Suid Site:
> document.activeElement
<body>…</body>
> document.querySelector('.MuiToolbar-root .MuiIconButton-root').click()
undefined
> document.activeElement
<body style="overflow: hidden;">…</body>
The problem occurs here:
|
return ( |
|
<TransitionContext.Provider |
|
value={{ |
|
get in() { |
|
return !!props.transition && props.open; |
|
}, |
|
onEnter: () => { |
|
props.transition && setExited(false); |
|
}, |
|
onExited: () => { |
|
if (props.transition) { |
|
setExited(true); |
|
if (props.closeAfterTransition) handleClose(); |
|
} |
|
}, |
|
}} |
|
> |
|
<Show when={!noMount()}> |
|
<Portal container={props.container} disablePortal={props.disablePortal}> |
|
{/* |
|
* Marking an element with the role presentation indicates to assistive technology |
|
* that this element should be ignored; it exists to support the web application and |
|
* is not meant for humans to interact with directly. |
|
* https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-static-element-interactions.md |
|
*/} |
|
<Dynamic |
|
{...otherProps} |
|
component={Root()} |
|
role="presentation" |
|
{...rootProps()} |
|
{...(!isHostComponent(Root()) && { |
|
//component: baseProps.component, |
|
ownerState: allProps, |
|
})} |
|
onKeyDown={handleKeyDown} |
|
class={clsx(classes.root, rootProps().class, otherProps.class)} |
|
ref={element} |
|
> |
|
<Show when={!props.hideBackdrop && !!props.BackdropComponent}> |
|
<Dynamic |
|
component={props.BackdropComponent} |
|
open={props.open} |
|
onClick={handleBackdropClick} |
|
{...(props.BackdropProps ?? {})} |
|
/> |
|
</Show> |
|
{props.children} |
|
</Dynamic> |
|
</Portal> |
|
</Show> |
|
</TransitionContext.Provider> |
|
); |
|
}); |
In Mui, a TrapFocus component handles focus management:
https://github.com/mui/material-ui/blob/89617ef683d2bcd2c870e9c1bd58ad4d55247fd5/packages/mui-base/src/ModalUnstyled/ModalUnstyled.js#L268-L290
Description
When using the temporary variant drawer and opening it, the browser warns:
Reason
Unexpected
aria-hiddenBased on my diagnosis, SUID incorrectly adds
aria-hiddento thedivused for mounting MuiModal.<body style="overflow: hidden"> <div id="root" aria-hidden="true">...</div> + <div aria-hidden="true"> <div class="MuiModal-root MuiDrawer-root MuiDrawer-modal MuiDrawer-root MuiModal-root css-o6o9lwg9" role="presentation" > <div aria-hidden="true" class="MuiBackdrop-root MuiModal-backdrop MuiBackdrop-root css-bh4oe82h" style="opacity: 1; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1)" ></div> <div class="MuiPaper-root MuiPaper-elevation MuiPaper-elevation16 MuiDrawer-paper MuiDrawer-paperAnchorRight MuiDrawer-paper MuiPaper-root css-cslrtd3y_1" style="transform: none; transition: transform 225ms cubic-bezier(0, 0, 0.2, 1)" > ... </div> </div> </div> </body>After reviewing the code, I found the issue originates here:
suid/packages/base/src/ModalUnstyled/ModalManager.ts
Lines 205 to 208 in d344de6
SolidJS's
Portalnests adivwhen passingmodal.refto the body instead of direct attachment. This causes theariaHiddenSiblingsfunction to consistently fail to exclude the current drawer element.A similar issue exists here:
suid/packages/base/src/ModalUnstyled/ModalManager.ts
Lines 267 to 284 in d344de6
However, replacing these
model.refwithmodal.ref.parentElement!still fails to resolve the error.Unmanaged Focus
Further diagnosis reveals that SUID fails to handle focus management:
Mui Site:
Suid Site:
The problem occurs here:
suid/packages/base/src/ModalUnstyled/ModalUnstyled.tsx
Lines 187 to 239 in d344de6
In Mui, a
TrapFocuscomponent handles focus management:https://github.com/mui/material-ui/blob/89617ef683d2bcd2c870e9c1bd58ad4d55247fd5/packages/mui-base/src/ModalUnstyled/ModalUnstyled.js#L268-L290