mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
94.02k stars 32.3k forks source link

[Modal or Dialog]: Modal Background Overlap When Used in map() Without Unique id #44457

Closed Bittukr7479 closed 3 days ago

Bittukr7479 commented 3 days ago

Steps to reproduce

Screenshot 2024-11-18 171430

Current behavior

When using the Modal component inside a map() function without unique state or IDs:

  1. Clicking the "Open Modal" button for any item in the list opens all modals in the map() simultaneously.

  2. The Modal's backdrop (BackdropComponent) becomes darker or fully black, with each modal stacking a new backdrop.

  3. This occurs regardless of whether only one modal is intended to open.

Expected behavior

  1. Only the modal for the clicked item should open.
  2. The BackdropComponent should appear once and not stack or become overly dark, even when multiple modals are rendered.
  3. There should be no visual overlap or stacking issues with the modal's backdrop.

Context

I am trying to render multiple modals dynamically using a map() function for a list of items. Each modal should work independently. However, the issue arises when:

  1. The same state or ID is used for all modals.
  2. No unique identifier is provided for the Modal.

Your environment

npx @mui/envinfo ``` Don't forget to mention which browser you used. Output from `npx @mui/envinfo` goes here. ```

Search keywords: Dialog Modal

sai6855 commented 3 days ago

Please provide a github or sandbox link that shows the problem, the description are very unclear

Bittukr7479 commented 3 days ago

Exapmple code without UniqueID (issue):

import React, { useState } from 'react';
import { Box, Button, Modal } from '@mui/material';

const ModalIssueWithoutUniqueID = () => {
  const items = [1, 2, 3]; // Example data
  const [open, setOpen] = useState(false);

  const handleOpen = () => setOpen(true);
  const handleClose = () => setOpen(false);

  return (
    <div>
      {items.map((item) => (
        <div key={item}>
          <Button onClick={handleOpen}>Open Modal {item}</Button>
          <Modal
            open={open}
            onClose={handleClose}
            aria-labelledby="modal-title"
            aria-describedby="modal-description"
          >
            <Box
              sx={{
                position: 'absolute',
                top: '50%',
                left: '50%',
                transform: 'translate(-50%, -50%)',
                width: 300,
                bgcolor: 'background.paper',
                boxShadow: 24,
                p: 4,
              }}
            >
              <h2 id="modal-title">Modal {item}</h2>
              <p id="modal-description">
                This is the content of modal {item}.
              </p>
            </Box>
          </Modal>
        </div>
      ))}
    </div>
  );
};

export default ModalIssueWithoutUniqueID;

Exapmple code with UniqueID (alternative solution):

import React, { useState } from 'react';
import { Box, Button, Modal } from '@mui/material';

const ModalIssueExample = () => {
  const items = [1, 2, 3]; // Example data
  const [openStates, setOpenStates] = useState({});

  const handleOpen = (id) => {
    setOpenStates((prev) => ({ ...prev, [id]: true }));
  };

  const handleClose = (id) => {
    setOpenStates((prev) => ({ ...prev, [id]: false }));
  };

  return (
    <div>
      {items.map((item) => (
        <div key={item}>
          <Button onClick={() => handleOpen(item)}>Open Modal {item}</Button>
          <Modal
            open={!!openStates[item]}
            onClose={() => handleClose(item)}
            aria-labelledby={`modal-title-${item}`}
            aria-describedby={`modal-description-${item}`}
          >
            <Box
              sx={{
                position: 'absolute',
                top: '50%',
                left: '50%',
                transform: 'translate(-50%, -50%)',
                width: 300,
                bgcolor: 'background.paper',
                boxShadow: 24,
                p: 4,
              }}
            >
              <h2 id={`modal-title-${item}`}>Modal {item}</h2>
              <p id={`modal-description-${item}`}>
                This is the content of modal {item}.
              </p>
            </Box>
          </Modal>
        </div>
      ))}
    </div>
  );
};

export default ModalIssueExample;
sai6855 commented 3 days ago

@Bittukr7479 You need to maintain a separate open state for each modal. Currently, the same open state is being used for all modals, causing all of them to open when any button is clicked. I have updated the sandbox to track the open state for each modal individually.

https://stackblitz.com/edit/react-dekrb4?file=Demo.tsx

github-actions[bot] commented 3 days ago

👋 Thanks for using this project!

We use GitHub issues exclusively as a bug and feature requests tracker, however, this issue appears to be a support request.

For support with Material UI please check out https://mui.com/material-ui/getting-started/support/. Thanks!

If you have a question on Stack Overflow, you are welcome to link to it here, it might help others. If your issue is subsequently confirmed as a bug, and the report follows the issue template, it can be reopened.