Matthew Garrett
Matthew Garrett

Reputation: 71

Custom Menu Item in MUI Data Grid Toolbar

I'm currently using the Data Grid Toolbar (a feature of the Material-UI Data Grid component) because I want the Column Show/Hide component, but I also want to add my own menu item in the form of an IconButton with a Menu that opens when clicked. The issue is when you click said button, the Toolbar appears to re-render, which causes the Menu to lose its anchor and render in the upper left. Is there a special way to get an anchor within the Data Grid Toolbar for the Menu popper to appear in the correct location?

  function CustomToolbar() {
    return (
      <GridToolbarContainer>
        <Box
          height="65px"
          width="100%"
          display="flex"
          flexDirection="row"
          justifyContent="center"
        >
          <Box width="300px" display="flex" justifyContent="flex-start" alignItems="center">
            <GridToolbarColumnsButton sx={{ ml: 2 }} />
          </Box>
          <Box width="100%" alignSelf="center" textAlign="center">
            <Typography sx={{ flex: "1 1 100%" }} variant="h6" component="div">
              Title Goes Here
            </Typography>
          </Box>
          <Box width="300px" display="flex" justifyContent="flex-end" alignItems="center">
            <Tooltip title="Filter">
              <IconButton
                color="primary"
                component="span"
                disabled={loading}
                sx={{ mr: 2 }}
                onClick={handleMenuClick}
              >
                <FilterList />
              </IconButton>
            </Tooltip>
            <Menu
              id="basic-menu"
              anchorEl={anchorEl}
              open={open}
              onClose={() => handleClose(menuState, filters)}
              transformOrigin={{ horizontal: "right", vertical: "top" }}
              anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
              PaperProps={MenuProps}
            >
              <MenuItem /> //Clipped
              <MenuItem /> //Clipped
              <MenuItem /> //Clipped
             </Menu>
          </Box>
        </Box>
      </GridToolbarContainer>
    );
  }

Upvotes: 7

Views: 8867

Answers (1)

igor
igor

Reputation: 41

You must create the Toolbar component outside of your component that declares the DataGrid, and get the properties you need through the DataGrid's componentsProps property.

GridToolbarCustom Component:

type Props = {
  selectionModel: GridSelectionModel;
}

const GridToolbarCustom = ({ selectionModel }: Props) => {
  const [anchorElMenu, setAnchorElMenu] = useState<null | HTMLButtonElement>(null);
  const openMenu = Boolean(anchorElMenu);

  return (
    <GridToolbarContainer>
      <Grid container item xs>
        {/* default buttons */}
        <GridToolbarColumnsButton />
        <GridToolbarFilterButton />
        <GridToolbarDensitySelector />
        <GridToolbarExport />
      </Grid>

      <Grid>
        <Button
          variant="contained"
          size="small"
          disabled={selectionModel.length === 0}
          startIcon={<MoreVertIcon />}
          onClick={(event: MouseEvent<HTMLButtonElement>) => {
            setAnchorElMenu(event.currentTarget);
          }}
        >
          Actions
        </Button>

        <Menu
          id="menu-options"
          anchorEl={anchorElMenu}
          open={openMenu}
          onClose={() => {
            setAnchorElMenu(null);
          }}
        >
          <MenuItem /> //Clipped
          <MenuItem /> //Clipped
          <MenuItem /> //Clipped
        </Menu>
      </Grid>
    </GridToolbarContainer>
  );
}

export default GridToolbarCustom;

MyComponent:

import GridToolbarCustom from './GridToolbarCustom';

const MyComponent = () => {
  const [selectionModel, setSelectionModel] = useState<GridSelectionModel>([]);

  return (
    <DataGrid
      //Clipped
      components={{
        Toolbar: GridToolbarCustom,
      }}
      componentsProps={{
        toolbar: {
          selectionModel,
        },
      }}
      checkboxSelection
      onSelectionModelChange={(newSelectionModel) => {
        setSelectionModel(newSelectionModel);
      }}
      selectionModel={selectionModel}
    />
  );
};

Upvotes: 4

Related Questions