Material UI - Unblock scrolling when popover is opened

Viewed 16473

The scroll is blocked with Popover according to the new material-ui version doc.

When i open the popover, the scroll-bar of the web page suddenly disappeared and it's not the part of user experience in my opinion.

I wanna keep the scroll bar visible while popover is open.

I'm using Material-UI V3.8.1.

8 Answers

it can be fixed by using container props of Popover. container props is a node, component instance or function that returns either. The container will passed to the Modal component. By default, it uses the body of the anchorEl's top-level document object, so it's simply document.body most of the time. This default setting is making document removing scroll bar. So i just used its direct parent for container instead of default setting and it solved the problem. :)

<Popover
  open={...}
  anchorEl={...}
  anchorOrigin={...}
  container={this.AnchorEl.parentNode}
>

Thanks

The property you are looking for is called disableScrollLock. But using this, does not recalculate the modals positioning and you will have a floating modal in your application. Instead, as described by a few others here, the Popper should be used.

To implement the correct behavior you can use Popper with Clickawaylistener

According to the docs, it looks like if you want to retain the scroll bar, then you should use Popper instead of Popover.

I stumbled upon this question when trying to fix the same problem. Improving upon @Tommy's answer, I've found a working solution:

const NewPopover = (props) => {
  const containerRef = React.useRef();

  // Box here can be any container. Using Box component from @material-ui/core

  return (
    <Box ref={containerRef}>
      <Popover {...props} container={containerRef.current}>
        Popover text!
      </Popover>
    </Box>
  );
};

Just tried something now that seems to work. Use a Popper instead I have done something like this.

<Popper
    id={id}
    open={popoverOpen}
    anchorEl={anchorEl}
    placement="top-start"
    disablePortal={false}
    modifiers={{
      flip: {
        enabled: false
      },
      preventOverflow: {
        enabled: true,
        boundariesElement: "scrollParent"
      }
    }}
>

Then to get the click away desired effect mount a "mousedown" effect check if the popover is open if it is then check the click is inside of the popper element. If not close the modal.

Something like this for the mousedown effect, note remember to dismount it or you'll get a leak.

React.useEffect(() => {
    if (anchorEl) {
      document.addEventListener("mousedown", handleClick)
    } else {
      document.removeEventListener("mousedown", handleClick)
    }
   // Specify how to clean up after this effect:
   return function cleanup() {
      document.removeEventListener("mousedown", handleClick)
   }
}, [anchorEl])

const handleClick = event => {
    if (!document.getElementById(id).contains(event.target)) {
       setAnchorEl(null)
       setCustomOpen(false)
    }
 }

Also just incase you are unsure theres another difference with Popper and Popover and that's just adding a Paper, but i don't need to explain how to do that.

I found another Solution that fits my case:

Just added a useEffect and attached a mouse wheel attempt to it close the popover:

function myPopover({/*..your props..*/}){
    const [open,setOpen] = useState(flase);
    //.... your rest of the code
    function handleClose(){
         setOpen(false);
    }
    useEffect(()=>{
        if(open){
            document.body.onwheel = handleClose; 
            document.body.addEventListener('touchstart', handleClose, false);

        }
        return ()=>{
            document.body.onwheel = undefined;
            document.body.removeEventListener('touchstart', handleClose, 
                   false);
        }
    },[open])
    return <Popover
      open={open}
      onClose={handleClose}
      anchorEl={...}
      anchorOrigin={...}
      /*... your props */
    >
}

I solved this with

html {
  overflow: visible !important;
}

Since Material-ui adds style="overflow: hidden;" on the html tag.

Related