Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can Material-UI's Dialog allow interaction behind the dialog?

I am using Material-UI in my React app, and I have a Dialog that appears over several form elements after I click a button.

I also have that dialog set to allow it to be dragged using react-draggable.

When the dialog is showing, none of the form elements behind it are ale to be accessed. I realize it intuitively makes sense to block interaction with the elements behind the dialog.

However, I am trying to figure out how to have the dialog showing, and yet still being able to edit the form elements behind it.

Code example here:

Does anyone know if it's possible to show a MaterialUI Dialog and still be able to interact with form elements behind the dialog (ie, when the dialog is dragged away)?

like image 579
Brett Avatar asked Dec 31 '22 03:12

Brett


2 Answers

The dialog was meant to block all other interaction so the user can focus on its contents. Anyway, I found one solution, probably not the better but is working here, the code is this:

<Dialog
  hideBackdrop // Disable the backdrop color/image
  disableEnforceFocus // Let the user focus on elements outside the dialog
  style={{ position: 'initial' }} // This was the key point, reset the position of the dialog, so the user can interact with other elements
  disableBackdropClick // Remove the backdrop click (just to be sure)
  ...
>
  ...
</Dialog>

Here a working example

like image 92
Fernando Gomes Avatar answered Jan 13 '23 12:01

Fernando Gomes


It is possible, and without too much trouble! When the Dialog is opened, its root container is a div with a class of MuiDialog-root, spawned directly in your <body>. Instead of putting the react-draggable component around the dialog's PaperComponent, we put it around the entire dialog:

<Draggable 
  handle={'[class*="MuiDialog-root"]'} 
  cancel={'[class*="MuiDialogContent-root"]'}>
    <Dialog 
      // Styling goes here
     > 
     ... // Dialog contents
    </Dialog>
</Draggable>

Then, it's necessary to style the Dialog a little. We need to make sure to disable the backdrop, then bring the container size down so that when we click behind it, we are actually selecting other components:

<Dialog
    open={open}
    onClose={handleClose}
    disableEnforceFocus // Allows other things to take focus
    hideBackdrop  // Hides the shaded backdrop
    disableBackdropClick  // Prevents backdrop clicks
    PaperComponent={PaperComponent}
    style={{
        top: '30%', // Position however you like
        left: '30%',
        height: 'fit-content',  // Ensures that the dialog is 
        width: 'fit-content',   // exactly the same size as its contents
    }}
    >
...
</Dialog>

Note the PaperComponent property. As per the material-ui docs on draggable dialogs, this refers to the surface that holds the dialog contents. However, instead of wrapping the paper in a <Draggable>, we need to create this component for styling. If we don't, the PaperComponent will have large, obnoxious margins and won't fit properly in its parent.

function PaperComponent(props: PaperProps) { 
// PaperProps is an import from '@material-ui/core'
    return (
        <Paper {...props} style={{ margin: 0, maxHeight: '100%' }} />
    );
}

Be sure to place this function outside of the rendering component. Otherwise, every time the state changes, your dialog contents will be remounted. This was bad for me because I was using an Autocomplete field in the dialog, and every time I selected an option and did something with the onChange(), the text input would disappear. Changing the function scope fixed this problem.

like image 27
April Avatar answered Jan 13 '23 13:01

April