skip to Main Content

I have MUI dialog which when I clickAway outside it can’t be removed. I want to add a shake effect or any effect to the dialog when the user clicks away so the user knows that clicking away is blocked. Besides, I want to prevent the user to use the Esc button to remove the dialog too.
The suggested answer could solve my question partially, just the Esc button using disableEscapeKeyDown attribute but not the rest of my question as disableBackdropClick can’t be applied.

This is my code. The clickAway is applied in the handleClose function. But I want to add an effect so that the user knows that clicking away isn’t allowed and prevent from using the Esc button to remove the dialog. Any suggestions? I couldn’t find any solution atm. Thanks

export const StatusModalFail = (): ReactElement => {
  const [open, setOpen] = useState(true);

  const handleClose = (event, reason) => {
    if (reason !== 'backdropClick') {
      setOpen(false);
    }
  };

  const handleCloseButton = () => {
    setOpen(false);
  };

  return (
    <Stack
      justifyContent="center"
      alignItems="center"
    >
      <Dialog
        open={open}
        PaperProps={{
          sx:{
            width: '100%',
            maxWidth: '500px!important',
            height:'100%',
            maxHeight:'250px!important',
          },
        }}
        onClose={handleClose}
      >
        <DialogContent>
          <Box
            sx={{
                  display: 'flex',
                   justifyContent: 'center',
                  alignItems: 'center',
            }}
          >
            <CrossIcon
              style={{
                    color: '#fa6757',
                    width: 48,
                    height: 48,
                    padding: 30,
              }}
            />
          </Box>

2

Answers


  1. You can prevent the MUI Dialog from closing when pressing the Esc button by setting the disableEscapeKeyDown prop to true. To add a shake effect when the user clicks away, you can create a custom backdrop component to handle click events and apply the shake effect. Here’s how you can modify your code:

    1. First, create the shake effect using keyframes:
    import { keyframes } from '@emotion/react';
    
    const shakeAnimation = keyframes`
      10%, 90% {
        transform: translate3d(-1px, 0, 0);
      }
      
      20%, 80% {
        transform: translate3d(2px, 0, 0);
      }
    
      30%, 50%, 70% {
        transform: translate3d(-4px, 0, 0);
      }
    
      40%, 60% {
        transform: translate3d(4px, 0, 0);
      }
    `;
    
    1. Create a custom Backdrop component:
    import Backdrop from '@mui/material/Backdrop';
    
    const CustomBackdrop = (props) => {
      const handleClick = (event) => {
        const dialogElement = document.getElementById('custom-dialog');
        if (dialogElement) {
          dialogElement.style.animation = `${shakeAnimation} 0.5s linear`;
          setTimeout(() => {
            dialogElement.style.animation = '';
          }, 500);
        }
        event.stopPropagation();
      };
    
      return <Backdrop {...props} onClick={handleClick} />;
    };
    
    1. Update the Dialog component to use the CustomBackdrop component, remove the onClose prop, and set the disableEscapeKeyDown prop to true:
    <Dialog
      id="custom-dialog"
      open={open}
      PaperProps={{
        sx: {
          width: '100%',
          maxWidth: '500px!important',
          height: '100%',
          maxHeight: '250px!important',
        },
      }}
      BackdropComponent={CustomBackdrop}
      disableEscapeKeyDown
    >
    

    Now, the Dialog will have a shake effect when clicking away, and the Esc button will not close it.

    Login or Signup to reply.
  2. This is example on how you can do it. I provide the codesanbox here:
    https://codesandbox.io/s/hardcore-wing-0mvnqc?file=/demo.js

    • create new state to handle when you need to shake/animate the dialog

      const [shake, setShake] = React.useState(false);

    • in handleClose function:

      const handleClose = (e, reason) => {
          if (reason !== "backdropClick" && reason !== "escapeKeyDown") {
            setOpen(false);
          }
         if (reason === "backdropClick" || reason === "escapeKeyDown") {
           setShake(true);
          }
       };
    
    • pass the shake state as a prop to your dialog component
       <BootstrapDialog
           shake={shake}
           ...
    
    • that way you can call the shake state inside the styled dialog
       const BootstrapDialog = styled(Dialog)(({ theme, shake }) => ({
    
    • and use it to determine whether you want to activate the animation or not. You will need to point at .MuiDialog-container to apply the animation:
     "& .MuiDialog-container": {
       animation: `${!shake ? "none" : `${myEffect} 1s infinite !important`}`
     }
     // define myEffect using keyframe imported from @emotion/react
     
    
    • keyframe example here (you can customize it as you need)

        const myEffect = keyframes`
          0% { transform: translateX(0) }
          25% { transform: translateY(-9px) }
          35% { transform: translateY(-9px) rotate(17deg) }
          55% { transform: translateY(-9px) rotate(-17deg) }
          65% { transform: translateY(-9px) rotate(17deg) }
          75% { transform: translateY(-9px) rotate(-17deg) }
          100% { transform: translateY(0) rotate(0) }
        `;
      
    • and you good to go.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search