Material-ui: [Modal] Scrollbar and padding issue

Created on 23 Jan 2018  ·  47Comments  ·  Source: mui-org/material-ui

When a Menu opens, the page's scrollbar disappears. This may affect page layout. In my case, it jumps everything over to the right, which is a visual bug.

Solution

Either A) fix this in the library, or B) Note this behavior in the docs, and provide ways of solving it:

https://material-ui-next.com/demos/menus/

The container for the things jumping is absolute, left: 0, right: 0, with sections that are either text-align: center or display: flex; flex-direction: column; align-items: center;

Your Environment

| Tech | Version |
|--------------|---------|
| Material-UI | 1.0.0-beta.29 |

Related issues

These are all closed, and I didn't find the solution in them:

8475 #7431 #6656 #8710

bug 🐛 Modal

Most helpful comment

The way I fixed it was just add disableScrollLock={ true } in my component :)

All 47 comments

In my case, it jumps everything over to the right, which is a visual bug.

@lorensr Do you have a reproduction example? It's a well-known limitation of disabling the scrollbar. We handle absolute positioned elements that have the .mui-fixed class name.
We need to document it!

FYI, another thing I've found is that the .mui-fixed fix only works if your fixed element also has

box-sizing: content-box;

Thanks, adding the class worked. I didn't need content-box. The element is border-box.

It should also be noted that when the scroll bar is removed, the block header inside my right: 0 element didn't stretch to the right edge of the browser.

image

Fixed by changing right: -20px, so now css is:

main {
  position: absolute;
  box-sizing: border-box;
  left: 0;
  right: -20px;
  overflow-x: hidden;
}

The downside is that when the scrollbar is present, centered children are now 10 pixels to the right of center, and I have to hide overflow.

In some cases it's not possible to apply the mui-fixed css class to some fixed elements. For example the crisp chat widget at the bottom of my page. Probably happens with intercom widget as well.

Does anyone else have the same problem and found a solution?
localhost_4000

I had a similar issue, but the container was not absolute. What fixed it for me was adding !important to my padding like this:

padding: 0 !important;

I'm not 100% sure if this is the correct way to do it but i added the following css properties to the <body> tag

```css
body {
position: absolute;
left: -17px;
right: -17px;
padding-top: 0;
padding-right: 17px;
padding-left: 17px;
padding-bottom: 0px;
overflow-x: hidden;
overflow-y: auto !important //Remove the !important if you want the scroll bar to disappear
}
````

Hopefully this helps someone else:

After trying some various css overrides that seemed to work but felt wrong, such as @chrisshaddad's, I found we were getting shifting due to previously forcing overflow-y: scroll on our whole app. We had forced the y-axis scrollbar app-wide to prevent shifting due to our pages having varying lengths - some requiring y-axis scrolling, some not.

Instead of placing a bunch of extra body or inline styling, we were able to fix the shifting by isolating the overflow-y: scroll to the content below our fixed AppBar/Header. Now we have an evergreen scrollbar for the page content, rather than the whole window, along with no shifting from modals/menus since the scrollbar is attached to the page content and not the body.

For reference our DOM looks like:

<div>
  <Header />
  <div className="pageContent">
    <div className="page">
      <Route exact path="/pathToPage"> component={PageContent} />
    </div>
  </div>
</div>

and the CSS (our header's height is 45px):

.pageContent {
  position: absolute;
  top: 45px;
  left: 0;
  right: 0;
  bottom: 0;
}
.pageContent .page {
  height: 100%;
  overflow-y: scroll;
}

Hello,

I currently have this same problem and I must admit that I cannot find my happiness in any of the solutions mentioned.

From what I understood, Modal does not allow to use the scrollbar, which is problematic because I use a Modal to perform an advanced search and a Modal doesn't always need to have a short content.

Thinking about the problem and the solutions you mentioned, I was wondering why it would not be possible for Material-UI to implement a scrollable property for everything related to Modal, Dialog, Menu and other popup elements. By default, this boolean property would be false, but could be true to allow a scrollbar to be displayed in the component.

If this is not possible, maybe implement a ScrollBar component outright, even if I prefer the idea before.

I suspect that this is easier said than done. I would therefore like to thank you for the exceptional work you are doing.

FWIW I just set a global body { overflow-y: scroll } and everything seems to work nicely.

@avdd This does not help since it will allow you to scroll in the body and not in the modal.

@rememberYou The modal is a low level primitive, you might want to use the dialog instead: https://material-ui.com/demos/dialogs/#scrolling-long-content.

@rememberYou ModalManager sets overflow:hidden directly on the container element (body) when the modal is visible and resets it when the modal is finished, so, yes it does work for me.

https://github.com/mui-org/material-ui/blob/7d4aeaf4c9cdf00a9c7eb41bd9bb7cac61840739/packages/material-ui/src/Modal/ModalManager.js#L24

@oliviertassinari thank you for the solution.
@avdd my apologies, I didn't try with the ModalManager.

@lorensr Is this still an issue?

@oliviertassinari One last thing, I tried with the Dialog, it works well, but since I want a more particular design, I like to use the Modals.

The issue is that I have a Modal (Login) that has a link to open a second Modal (SignUp) that itself has a link to return to the Login.

In this case, do I have to use the ModalManager to easily add and remove a Modal? Sorry to get out of the subject of the issue, I didn't find any documentation on the subject.

@nathanmarks yes, looks like modal components docs pages still don't mention .mui-fixed

Using 3.5.1 - the Dialog shifts to the left before closing.

Reproducible here https://material-ui.com/demos/dialogs/ - open and close the Simple Dialog demo.

After testing, this started in v3.3.

@stephen099 Thank you for reporting! I confirm, but it's a different issue.

I've noticed that on the header (with the latest mui), the mui-fixed is added to the class names, but there is no styling assigned to it (by inspecting the header, there is no mui-fixed rule loaded.

I'm wondering, why is this 'add padding' happening in the first place, why is it needed? For me it's broken by the Menu component.

How do I prevent this from happening without having to override the css styling with !important ... ? Thanks

@vajnorcan The mui-fixed class name signals the modal component (used by the menu) that the element position will change when locking the scroll on the body element. We compensate for the scrollbar width removal with a temporary padding-right style. Could you provide a minimal reproduction example on CodeSandbox? Thank you.

Sorry where do you put the .mui-fixed ? I have this problem with a select opening a menu.

@capsule5 You need to add it to the element that "jumps" due to the scrollbar being disabled on menu open (usually this should be an element fixed to the right) and its padding will be handled for you.

Also note that, as mentioned above, you may need to add this to your global styles:

.mui-fixed {
  /*
   * make sure that added right padding
   * actually pushes contents to the left
   */
  box-sizing: content-box;
}

There is no reproduction in this thread. I'm closing.

@cvara We keep track of it in #9275.

I don't get it, is this solved? I upgraded from v0.9 to v4 and now when I open modals my content jumps to the left (getting padding-right: 17px)? What's the recomended solution for it?

Later edit:

Because in my case I had overflow-y: scroll !important; I also had to add padding-right: 0px !important; to fix this jumping issue.

The way I fixed it was just add disableScrollLock={ true } in my component :)

@Toshiuk which component?

@wongjiahau the Modal component v4+

You can also add disableScrollLock to Menu

This is reproducing for me as well. Adding disableScrollLock is not plausible since I am using third party components that add the Menu items. This should be fixed. Maybe detect that the scrollbar actually displays or not.

@archfz Do you have a reproduction?

I'm witnessing this in use of Select components as well. Whenever a Select dropdown is opened, overflow: hidden, padding-right: 15px is added to the main body tag of my app. Is there a solution this besides overriding styles? I feel like this isn't expected behavior

@WholemealDrop Follow #17353.

@oliviertassinari ahah apparently my search skills aren't that great. Thank you!

@oliviertassinari I have managed to reduce the problem to the core. The issue seems to be that somehow there is incorrect calculations when display: flex + minHeight: 100vh + body no padding and margin is combined. It seems like that the code expects to be a scrollbar there but in fact there is not. This code should reproduce the issue.

import React, {FunctionComponent, SyntheticEvent, useState} from 'react';
import {IconButton, Menu, MenuItem, Tooltip} from "@material-ui/core";
import TranslateIcon from "@material-ui/icons/Translate";
import MuiAppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";

const AdminAppContainer: FunctionComponent = () => {
  const handleMenu = (event: SyntheticEvent) => setAnchorEl(event.currentTarget);
  const [anchorEl, setAnchorEl] = useState<Element | null>(null);
  const open = Boolean(anchorEl);
  const handleClose = () => setAnchorEl(null);

  const body = document.getElementsByTagName('body')[0];
  body.style.margin = "0";
  body.style.padding = "0";

  return (
    <div style={{ display: 'flex', minHeight: '100vh'}}>
    <MuiAppBar color="secondary" >
      <Toolbar>
        <div style={{flex: 1}}></div>
        <div>
          <Tooltip title='asd'>
            <IconButton onClick={handleMenu}><TranslateIcon /></IconButton>
          </Tooltip>
          <Menu anchorEl={anchorEl} open={open} onClose={handleClose}>
            <MenuItem key={'test'} onClick={handleClose}>Test</MenuItem>
          </Menu>
        </div>
      </Toolbar>
    </MuiAppBar>
    </div>
  )
};

@archfz Could you create a codesandbox please? (You could start with one of the docs examples.)

@archfz Sorry, missed this.

What am I looking for here? I don't experience any layout changes.

@archfz Sorry, missed this.

What am I looking for here? I don't experience any layout changes.

When you click on the character in the top right, it moves to the left when the menu item opens and then moves back to the right when the menu item closes.

Could you open a new issue? It seems something new.

@archfz Ok, it's a conflict with the tooltip. Let's ignore it.

@oliviertassinari Well we should not ignore it cause it's a real issue. React-admin uses material UI and it actually is an issue out of the box. I have created an issue here https://github.com/mui-org/material-ui/issues/19203

The solution re-iterated by @Toshiuk is to simply add the following:

  • Menu, StyledMenu:
    disableScrollLock={ true }

  • Select:
    MenuProps={{ disableScrollLock: true }}

We really need to make solutions more easily findable! :-)

I have problem with background color of toolbar when I open menu, and scrollbar become invisible

here is example:
https://codesandbox.io/s/material-demo-nj80l

know somebody how it fix?

just add the following css
body { padding-right: 0px !important; }

hello, in my app i use this solution.
I add disableScrollLock={true} disablePortal={true} id="custom" on my component <Menu> and in my css
#custom { .MuiPopover-paper, .MuiPopover-paper { max-height: inherit !important; } }
this work perfectly in my case. I hope this tricks can help.

I experienced the same problems working with Dialogs. The following is the only solution that I have tried that both removes the shifting of content and still locks the scroll of the underlying page/removes its scrollbar.

Solution:
Go to the outermost container div or any outermost div (any container that encapsulates your entire app) in your app and set its width to this:

width: calc(100vw - 1px);

1px can be substituted with 34px or any other low value. This will make it so that opening a Dialog will hide the scroll bar of the underlying page, if present, and will not create any sort of shift in the position of the content. Scrolling is still locked for the underlying page and scrolling is still possible for your dialog.

disableScrollLock={ true }

You are just brilliant, Thank you

Was this page helpful?
0 / 5 - 0 ratings