mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
4.03k stars 1.24k forks source link

[data grid] Cell stealing focus from modal and onClicks for buttons rendered inside cells fire when the user hits the enter key #13824

Closed RyleySill93 closed 1 month ago

RyleySill93 commented 1 month ago

Steps to reproduce

Link to live example: https://codesandbox.io/s/interesting-bell-nhwlvx?file=/src/Demo.tsx

Grid cell stealing focus from dialog issue:

  1. Click on a button in the grid
  2. Try to type into the input in the dialog (or double click the dialog anywhere)
  3. The grid cell steals focus from the dialog

Buttons on click is fired when hitting "enter" into the cell it's rendered within:

  1. Click in the margins of one of the cells rendering a button to focus that cell
  2. Hit enter twice (once to enter the editor, twice to go to the next cell below)
  3. Somehow the onClick for the button in the cell is fired

Current behavior

No response

Expected behavior

No response

Context

For the stealing focus issue, I'm rendering a complex modal with many inputs so I don't want to spam e.stopPropagation() everywhere - ideally I'd be able to programmatically unfocus the cell when I open the modal so any events happening within the modal aren't forwarded to the cell.

Your environment

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

Search keywords: DataGrid steal focus onClick enter button cell Order ID: 75803

michelengelen commented 1 month ago

Hey @RyleySill93 these issues are to be handled separately:

  1. The reason the focus gets stolen is that the Dialog is being rendered within the cell and the keyDown event bubbles up to the cell. To prevent this (and improve general performance) you would be better off to render the Dialog component outside of the DataGrid and handle changes through the API.
export default function DataGridDemo() {
  const [openId, setOpenId] = React.useState(null);

  const CustomCell = (value) => (
    <Button variant="contained" onClick={() => setOpenId(value.id)}>
      button
    </Button>
  );

  const columns: GridColDef<(typeof rows)[number]>[] = [
    {
      field: 'id',
      headerName: 'ID',
      width: 150,
      editable: true,
      renderCell: CustomCell,
    },
  ];

  return (
    <Box sx={{ height: 400, width: '100%' }}>
      <DataGrid
        rows={rows}
        columns={columns}
        initialState={{
          pagination: {
            paginationModel: {
              pageSize: 5,
            },
          },
        }}
        pageSizeOptions={[5]}
        checkboxSelection
        disableRowSelectionOnClick
      />
      <Dialog onClose={() => setOpenId(null)} open={!!openId}>
        <Box p={5}>
          <TextField />
        </Box>
      </Dialog>
    </Box>
  );
}
  1. For this case I am not 100% sure what happens. A quick investigation show that the dialog opens for the following row, not the one that got edited just now. So the immediate thought is that the grid focusses the next cell and fires an event to start editing mode and that is resembling an onClick for some reason.

@romgrk could you have a look at the second case! I feel I might be missing something here

romgrk commented 1 month ago

The focus management logic for cells is here. The cell edit stop event runs on keydown, and that logic moves the focus to the button in the next cell. The keypress event that follows then clicks on the button because the key is Enter.

I would suggest running event.preventDefault() on the cellEditStop event for those cells. It's a bit messy but cell editing wasn't meant to also have interactive display-mode cells (the buttons).

https://codesandbox.io/p/sandbox/goofy-edison-9rr7dm?file=%2Fsrc%2FDemo.tsx%3A3%2C37

github-actions[bot] commented 1 month ago

The issue has been inactive for 7 days and has been automatically closed.