Search code examples
reactjsmaterial-uimui-datatable

MUI DataGrid - Open GridColumnsPanel


In the MUI DataGrid, by clicking the options menu on any header column, you can access the column visibility panel.

But I haven't found a way to display this panel from outside the Grid. The idea was to have a button that, when clicked, could display the panel. Even if it remains with its position inside the Grid

This would avoid having to build a component for this purpose.

example: example


Solution

  • I'm not sure if I missed it in the docs, but it doesn't look like you can control the visibility of the default MUI 'Column Visibility Panel' with the Grid API like you can with the Filter Panel.

    However, you can provide your own columnVisibilityModel to the DataGrid which will dictate which columns are visible in the grid. This will let you control the visibility of each column from outside the grid, but you will have to create your own Column Visibility Panel.

    Here is a code sandbox example: https://codesandbox.io/s/mui-5-forked-zj4glu?file=/src/ArrowPopper.tsx

    Code:

    import * as React from "react";
    import { Box, Button, FormControlLabel, Popper, Switch } from "@mui/material";
    import { DataGrid, GridColDef, GridValueGetterParams } from "@mui/x-data-grid";
    
    const columns: GridColDef[] = [
      { field: "id", headerName: "ID", width: 90 },
      {
        field: "firstName",
        headerName: "First name",
        width: 150,
        editable: true
      },
      {
        field: "lastName",
        headerName: "Last name",
        width: 150,
        editable: true
      },
      {
        field: "age",
        headerName: "Age",
        type: "number",
        width: 110,
        editable: true
      },
      {
        field: "fullName",
        headerName: "Full name",
        description: "This column has a value getter and is not sortable.",
        sortable: false,
        width: 160,
        valueGetter: (params: GridValueGetterParams) =>
          `${params.row.firstName || ""} ${params.row.lastName || ""}`
      }
    ];
    
    const rows = [
      { id: 1, lastName: "Snow", firstName: "Jon", age: 35 },
      { id: 2, lastName: "Lannister", firstName: "Cersei", age: 42 },
      { id: 3, lastName: "Lannister", firstName: "Jaime", age: 45 },
      { id: 4, lastName: "Stark", firstName: "Arya", age: 16 },
      { id: 5, lastName: "Targaryen", firstName: "Daenerys", age: null },
      { id: 6, lastName: "Melisandre", firstName: null, age: 150 },
      { id: 7, lastName: "Clifford", firstName: "Ferrara", age: 44 },
      { id: 8, lastName: "Frances", firstName: "Rossini", age: 36 },
      { id: 9, lastName: "Roxie", firstName: "Harvey", age: 65 }
    ];
    
    export default function DataGridDemo() {
      const [columnVisibility, setColumnVisibility] = React.useState({
        id: true,
        firstName: true,
        lastName: true,
        age: true,
        fullName: true
      });
    
      const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
    
      const toggleColumnVisibility = (e) => {
        setColumnVisibility((prev) => ({
          ...prev,
          [e.target.name]: e.target.checked
        }));
      };
    
      const handleClick = (event: React.MouseEvent<HTMLElement>) => {
        setAnchorEl(anchorEl ? null : event.currentTarget);
      };
    
      const open = Boolean(anchorEl);
    
      return (
        <Box sx={{ height: 400, width: "100%" }}>
          <Button
            onClick={handleClick}
            variant="contained"
            sx={{
              mb: 2
            }}
          >
            Show Column Visibility
          </Button>
          <DataGrid
            rows={rows}
            columns={columns}
            pageSize={5}
            rowsPerPageOptions={[5]}
            checkboxSelection
            disableSelectionOnClick
            columnVisibilityModel={columnVisibility}
          />
          <Popper open={open} anchorEl={anchorEl}>
            <Box
              sx={{
                display: "flex",
                flexDirection: "column",
                backgroundColor: "white"
              }}
            >
              {columns.map((c) => (
                <FormControlLabel
                  key={c.field}
                  label={c.headerName}
                  control={
                    <Switch
                      name={c.field}
                      checked={columnVisibility[c.field]}
                      onChange={toggleColumnVisibility}
                    />
                  }
                />
              ))}
            </Box>
          </Popper>
        </Box>
      );
    }