Skip to content

[material-ui][Modal] Apply aria-hidden to the correct elements when Modals are mounted to other places than document.body - #43318

Open
Gr3q wants to merge 53 commits into
mui:masterfrom
Gr3q:fix-modal-hiding
Open

[material-ui][Modal] Apply aria-hidden to the correct elements when Modals are mounted to other places than document.body#43318
Gr3q wants to merge 53 commits into
mui:masterfrom
Gr3q:fix-modal-hiding

Conversation

@Gr3q

@Gr3q Gr3q commented Aug 15, 2024

Copy link
Copy Markdown

Fixes #19450

Lets do #34165 again. Before if someone used disablePortal and opened a modal the whole page became inaccessible to Screen Readers because aria-hidden only got applied to siblings of document.body, in this case all of them. This PR fixes that.

Changes:

  • Make sure we pass in the correct container if disablePortal is used.
  • If the modal container is deep in the tree we need to make sure every sibling in every ancestor level is aria-hidden and every aria-hidden we added gets cleaned up properly on unmount.
  • In addition because we don't differentiate between aria-hidden tags that got added by modals and added by devs, we need to pierce through (remove) every aria-hidden attribute in every ancestor of the last modal container; this is to prevent no accessible elements on a page when multiple modals are present.

Known problems:

  • You will have a bad time if you put your dialog in a container next to 1000s of siblings - bad idea before, bad idea now.
  • Previous bug still stands when you mess with aria-hidden states in the tree outside your modal, when the modal gets removed your changes won't be preserved (because the modal will restore the state when it was added)

I'll port this to next too when I have time.

@mui-bot

mui-bot commented Aug 15, 2024

Copy link
Copy Markdown

Netlify deploy preview

https://deploy-preview-43318--material-ui.netlify.app/

Bundle size report

@mui/materialparsed: 🔺+320B(+0.06%) gzip: 🔺+160B(+0.10%)
@mui/labparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/systemparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/utilsparsed: 0B(0.00%) gzip: 0B(0.00%)

Details

Show details for 100 more bundles (86 more not shown)

@mui/material/Dialogparsed: 🔺+326B(+0.34%) gzip: 🔺+135B(+0.40%)
@mui/material/Modalparsed: 🔺+326B(+0.37%) gzip: 🔺+131B(+0.41%)
@mui/material/Menuparsed: 🔺+323B(+0.31%) gzip: 🔺+153B(+0.42%)
@mui/material/Popoverparsed: 🔺+323B(+0.33%) gzip: 🔺+143B(+0.41%)
@mui/material/Selectparsed: 🔺+323B(+0.23%) gzip: 🔺+143B(+0.30%)
@mui/material/SwipeableDrawerparsed: 🔺+322B(+0.31%) gzip: 🔺+136B(+0.37%)
@mui/material/Drawerparsed: 🔺+321B(+0.33%) gzip: 🔺+122B(+0.35%)
@mui/material/TextFieldparsed: 🔺+321B(+0.21%) gzip: 🔺+132B(+0.26%)
@mui/material/TablePaginationparsed: 🔺+320B(+0.18%) gzip: 🔺+140B(+0.25%)
@mui/lab/AdapterDateFnsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/AdapterDayjsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/AdapterLuxonparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/AdapterMomentparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/CalendarPickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/CalendarPickerSkeletonparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/ClockPickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/DatePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/DateRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/DateRangePickerDayparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/DateTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/DesktopDatePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/DesktopDateRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/DesktopDateTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/DesktopTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/LoadingButtonparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/LocalizationProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/Masonryparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/MobileDatePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/MobileDateRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/MobileDateTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/MobileTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/MonthPickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/PickersDayparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/StaticDatePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/StaticDateRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/StaticDateTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/StaticTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TabContextparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TabListparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TabPanelparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/Timelineparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TimelineConnectorparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TimelineContentparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TimelineDotparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TimelineItemparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TimelineOppositeContentparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TimelineSeparatorparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TreeItemparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/TreeViewparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/useAutocompleteparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/lab/YearPickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Accordionparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/AccordionActionsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/AccordionDetailsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/AccordionSummaryparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Alertparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/AlertTitleparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/AppBarparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Autocompleteparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Avatarparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/AvatarGroupparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Backdropparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Badgeparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/BottomNavigationparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/BottomNavigationActionparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Boxparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Breadcrumbsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Buttonparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/ButtonBaseparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/ButtonGroupparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Cardparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/CardActionAreaparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/CardActionsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/CardContentparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/CardHeaderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/CardMediaparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Checkboxparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Chipparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/CircularProgressparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/ClickAwayListenerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Collapseparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Containerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/CssBaselineparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/DefaultPropsProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/DialogActionsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/DialogContentparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/DialogContentTextparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/DialogTitleparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Dividerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Fabparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Fadeparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/FilledInputparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/FormControlparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/FormControlLabelparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/FormGroupparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/FormHelperTextparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/FormLabelparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/GlobalStylesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/material/Gridparsed: 0B(0.00%) gzip: 0B(0.00%)

Details of bundle changes

Generated by 🚫 dangerJS against 0696317

@Gr3q Gr3q changed the title [Modal] Apply aria-hidden to the correct Elements in the tree when Modals are mounted to to other places than document.body [ModalManager] Apply aria-hidden to the correct Elements in the tree when Modals are mounted to to other places than document.body Aug 15, 2024
@Gr3q Gr3q changed the title [ModalManager] Apply aria-hidden to the correct Elements in the tree when Modals are mounted to to other places than document.body [ModalManager] Apply aria-hidden to the correct elements in the tree when Modals are mounted to other places than document.body Aug 15, 2024
@aarongarciah aarongarciah changed the title [ModalManager] Apply aria-hidden to the correct elements in the tree when Modals are mounted to other places than document.body [material-ui][Modal] Apply aria-hidden to the correct elements when Modals are mounted to other places than document.body Aug 16, 2024
@aarongarciah aarongarciah self-assigned this Aug 16, 2024
@zannager
zannager requested a review from mnajdova August 16, 2024 10:36
@Gr3q

Gr3q commented Aug 17, 2024

Copy link
Copy Markdown
Author

Your argos check seems to be borked especially I made no changed that would affect visuals.

@aarongarciah aarongarciah removed their assignment Sep 11, 2024
@ZeeshanTamboli
ZeeshanTamboli changed the base branch from v5.x to master September 20, 2024 06:41
@ZeeshanTamboli
ZeeshanTamboli changed the base branch from master to v5.x September 20, 2024 06:42

@ZeeshanTamboli ZeeshanTamboli left a comment

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.

@Gr3q, can you point the PR to the master branch, our current development branch for releases? I'll review it once that's done.

Your argos check seems to be borked especially I made no changed that would affect visuals.

I think its because the target branch is v5 and argos checks against master.

@Gr3q
Gr3q changed the base branch from v5.x to master September 20, 2024 10:31
@Gr3q

Gr3q commented Sep 21, 2024

Copy link
Copy Markdown
Author

Should I not touch the unstable folder in the future? Could you explain why does it exist?

@ZeeshanTamboli

ZeeshanTamboli commented Sep 21, 2024

Copy link
Copy Markdown
Member

Should I not touch the unstable folder in the future? Could you explain why does it exist?

I reverted the changes in Base UI (mui-base directory). It included the unstable folder because Base UI was still in beta. We no longer maintain Base UI in this repository—it's now legacy and will be removed in the future (timeline unknown). Material UI used to depend on Base UI, but we've since separated the code, causing duplication. We don't plan to make any further changes to Base UI here. The issue is related to Material UI's Modal. Base UI with headless components is now being developed in a separate repo: mui/base-ui, which will be integrated into Material UI once stable.

@ZeeshanTamboli ZeeshanTamboli left a comment

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.

@Gr3q Thanks for the pull request.

In addition because we don't differentiate between aria-hidden tags that got added by modals and added by devs, we need to pierce through (remove) every aria-hidden attribute in every ancestor of the last modal container; this is to prevent no accessible elements on a page when multiple modals are present.

I didn't understand this. Can you please explain more clearly with an example?

Previous bug still stands when you mess with aria-hidden states in the tree outside your modal, when the modal gets removed your changes won't be preserved (because the modal will restore the state when it was added)

What bug is this? Can you give a bug reproduction in the form of StackBlitz or CodeSandbox?

Comment thread packages/mui-material/src/Modal/ModalManager.test.ts Outdated
Comment thread packages/mui-material/src/Modal/ModalManager.test.ts Outdated
Comment thread packages/mui-material/src/Modal/ModalManager.test.ts Outdated
Comment thread packages/mui-material/src/Modal/ModalManager.test.ts
Comment thread packages/mui-material/src/Modal/ModalManager.test.ts Outdated
Comment thread packages/mui-material/src/Modal/ModalManager.ts
Comment thread packages/mui-material/src/Modal/ModalManager.ts
Comment thread packages/mui-material/src/Modal/ModalManager.ts Outdated
Comment thread packages/mui-material/src/Modal/useModal.types.ts Outdated
Comment thread packages/mui-material/src/Portal/Portal.tsx Outdated
Gr3q and others added 5 commits September 22, 2024 11:53
Co-authored-by: Zeeshan Tamboli <zeeshan.tamboli@gmail.com>
Signed-off-by: Attila Greguss <floyd0122@gmail.com>
Co-authored-by: Zeeshan Tamboli <zeeshan.tamboli@gmail.com>
Signed-off-by: Attila Greguss <floyd0122@gmail.com>
Co-authored-by: Zeeshan Tamboli <zeeshan.tamboli@gmail.com>
Signed-off-by: Attila Greguss <floyd0122@gmail.com>
@Gr3q

Gr3q commented Dec 19, 2024

Copy link
Copy Markdown
Author

As per the current production code, the prevention of scrolling is on the container, where the scrollContainer in the code is the resolvedContainer (either the one provided by the developer or the default body). If you inspect in https://mui.com/material-ui/react-modal/#server-side-modal, you will see overflow: hidden is applied on Box container.

You are right that the disablePortal={true} is the same as container. The container prop only has an effect when disablePortal={false}. When disablePortal={true}, the container prop is ignored since no portal is created. But I think it's about the scroll lock style getting applied on the container. What if a developer has a custom container and no disablePortal?
I think we will have to revert a few commits here till #43318 (comment).

I'm changing the code, but I want to summarize the bugs this PR had, then what you want.

Bugs:

  1. scrollLock doesn't work for disablePortal on the docs page - I found out the correct behaviour is to lock the body element (just like before) because that's the only way scroll locking works. When container is provided locking was applied to the container (and that didn't work, this is the bevaiour on the main branch)
  2. Because I changed (fixed) the scroll locking behaviour to always apply to body, the whole modal doc page got locked. This was due to the server-side modal always open with no disableScrollLock. disablePortal applied or not doesn't make a difference here.

So let me clarify what you want:

You want me to change it that scroll lock works peropely when:

  • disablePortal is set
  • disablePortal is not set

and it shouldn't work properly (aka scroll lock applies to the container that effectively does nothing to prevent page scrolling):

  • container is set, regardless if disablePortal is set or not. This means even though container is not used when disablePortal is true and the modal shouldn't be mounted to the container at all, you still want the scroll lock to apply to that container.

I want you to confirm this because this is the only way bugs 1 and 2 can be resolved on the Modal docs page at the same time. (Edit: I'm asking because I will need to implement some workarounds to handle that)

@ZeeshanTamboli

Copy link
Copy Markdown
Member

@Gr3q It's been a while, but from what I remember you're right—that's what's needed.

@Gr3q

Gr3q commented Jan 20, 2025

Copy link
Copy Markdown
Author

@ZeeshanTamboli I fixed the doc page, it does what you want (so no breaking changes).

Added a comment that technically the behaviour around the scrolllock+container is still a bug, hopefully someone will remove it when the next major version comes.

Fixed the existing tests and added new tests for this too.

So now the PR should be ready. 🤞

@ZeeshanTamboli ZeeshanTamboli left a comment

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.

@Gr3q This looks good to me. I left one comment.

I'm unsure if this will be considered since the focus is shifting to re-implementing Material UI with the new Base UI in the next major release or the one after. I appreciate the time you've invested in this, and I apologize in advance if it doesn’t move forward. However, it might still be possible to release this now or in the next major version. This will definitely need further review. @DiegoAndai, could you take a look?

Comment thread packages/mui-material/src/Modal/useModal.ts Outdated
@Gr3q

Gr3q commented Jan 28, 2025

Copy link
Copy Markdown
Author

@Gr3q This looks good to me. I left one comment.

I'm unsure if this will be considered since the focus is shifting to re-implementing Material UI with the new Base UI in the next major release or the one after. I appreciate the time you've invested in this, and I apologize in advance if it doesn’t move forward. However, it might still be possible to release this now or in the next major version. This will definitely need further review. @DiegoAndai, could you take a look?

I think it's still be a while that is released, so it's worth fixing the current version now.

@DiegoAndai
DiegoAndai requested review from DiegoAndai and removed request for mnajdova January 28, 2025 18:03
@DiegoAndai

Copy link
Copy Markdown
Member

Hey @Gr3q and @ZeeshanTamboli. First of all, thanks for working on this 🙌🏼

I'm unsure if this will be considered since the focus is shifting to re-implementing Material UI with the new Base UI in the next major release or the one after.

While true, we can still accept and review improvements from the community regarding these topics. So, let's keep working on this. We can land it in v7, which will help many people (given the number of upvotes in the issue).

The first thing I would say is that we should change to using aria-modal. Would that be possible? That would remove the need to traverse the DOM by applying/removing aria-hidden, which would greatly simplify the implementation.

It will be a breaking change, but we're already on v7 on the master branch, so we should make it.

Let me know what you think.

@ZeeshanTamboli

ZeeshanTamboli commented Jan 29, 2025

Copy link
Copy Markdown
Member

The first thing I would say is that we should change to using aria-modal. Would that be possible? That would remove the need to traverse the DOM by applying/removing aria-hidden, which would greatly simplify the implementation.

See conversation from #43318 (review). That wasn't planned back then but maybe we can consider it now for a major release.

@DiegoAndai DiegoAndai left a comment

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.

Ok, I checked the discussion on this PR and also reached out to the Base UI team.

In conclusion, we are not able to stop using aria-hidden as I suggested. So I would say we should move forward with this PR's intention: fix aria-hidden handling when disablePortal is true.

Here's my initial review.

By the way, thanks for working on this @Gr3q

const isPreviousElement = element === previousElement;

// We came from here
if (isPreviousElement) {

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.

If isPreviousElement is true, it means that we're on the modal or one of its ancestors, right?

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, that is correct. Can happen if container is set to the same thing as the other args.

Comment on lines +84 to +85
// If any ancestor has aria-hidden applied (e.g. by another modal), the current modal could become inaccessible.
// We remove aria-hidden from ancestors to ensure the current modal is accessible, even though this might not be ideal if aria-hidden wasn't added by another modal (For example, if a developer manually applied aria-hidden to hide certain content, removing it could lead to unintended accessibility issues.).

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.

We shouldn't do this:

If multiple modals are open, or the developer applied aria-hidden to one of the modal's ancestors, it's the developer responsibility to fix it.

This is not an acceptable side-effect:

[...] if a developer manually applied aria-hidden to hide certain content, removing it could lead to unintended accessibility issues.

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 is the most important part of the fix. How do you propose me fixing this problem:

  1. Open a Modal with disablePortal
  2. Open another Modal with no disablePortal

No need for nesting modals etc, just do it programmatically. Now step one applied aria-hidden to the ModalManager's parent container, step 2 will apply aria-hidden to the parent of step one's Modal. Without that part it's completely inaccessible, no need for developer error.

If multiple modals are open , or the developer applied aria-hidden to one of the modal's ancestors, it's the developer responsibility to fix it.

Why would you expect the dev's to fix something that the library is doing to itself? How the hell would you fix this as a dev? ModalManager is not exposed, you can't replace it with something that actually works.

If multiple modals are open, or the developer applied aria-hidden to one of the modal's ancestors, it's the developer responsibility to fix it.

This one makes sense. Tell me, how would I go about tracking which ones were added by ModalManager, which ones are added by the dev, or my favorite case: when both are true?

Comment on lines +125 to +134
// Implement workaround according to
// https://github.com/mui/material-ui/pull/43318#issuecomment-2553509176
// Technically applying scrollLock to the container does nothing, but
// we preserve the original buggy behavior because fixing it would be
// a breaking change.
// Original behavior: Apply scroll lock to container if it's set,
// otherwise apply to the body element. Because disablePortal
// passes in the correct `containerInfo.container`, the easiest way to
// make it apply to the correct element is to do this.
const container = props.container ? containerInfo.container : document.body;

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.

Is this related to scroll locking and not aria-hidden? If so, we should move it to a separate PR

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.

If you do that scroll locking will be broken for disablePortal and you will still need to merge them in together.

This PR changed containerInfo.container so it's resolved correctly when disablePortal is used, making scroll locking ineffective (because basically it was always applied to body - which works - unless container was passed in, where it was also ineffective)

Comment on lines +92 to +94
const resolvedContainer = disablePortal
? ((mountNodeRef.current ?? modalRef.current)?.parentElement ?? getDoc().body)
: getContainer(container) || getDoc().body;

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.

If providing the container prop was required when using disablePortal, this could be simplified to

Suggested change
const resolvedContainer = disablePortal
? ((mountNodeRef.current ?? modalRef.current)?.parentElement ?? getDoc().body)
: getContainer(container) || getDoc().body;
const resolvedContainer = getContainer(container) || getDoc().body;

Right?

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.

But it's not required and it shouldn't be, because if you don't use Portal how could you mount it to a different container?

That is also the reason disablePortal takes priority over container here.

@github-actions github-actions Bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Apr 26, 2025
@github-actions github-actions Bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged. label Jun 13, 2025
@joshkel

joshkel commented Dec 4, 2025

Copy link
Copy Markdown
Contributor

We ran into this bug again today. Is there anything I can do to help move the PR along?

Thank you.

@github-actions github-actions Bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Dec 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

accessibility a11y PR: out-of-date The pull request has merge conflicts and can't be merged. scope: modal Changes related to the modal.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Modal] aria-hidden should not be applied on non-portal modals

7 participants