Wallace Roversi
Wallace Roversi

Reputation: 73

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

Upvotes: 7

Views: 2463

Answers (2)

Linda Paiste
Linda Paiste

Reputation: 42208

This section of the grid is called the GridPreferencesPanel. You can open it imperatively by using the showPreferences function on the grid API. Here is the documentation from the MUI source code:

/**
 * The preferences panel API interface that is available in the grid [[apiRef]].
 */
export interface GridPreferencesPanelApi {
    /**
     * Displays the preferences panel. The `newValue` argument controls the content of the panel.
     * @param {GridPreferencePanelsValue} newValue The panel to open. Use `"filters"` or `"columns"`.
     */
    showPreferences: (newValue: GridPreferencePanelsValue) => void;
    /**
     * Hides the preferences panel.
     */
    hidePreferences: () => void;
}

The same function is used for opening the filters menu and the columns menu so you will need to pass the correct argument to determine which to show. Your example image depicts the columns menu. If you are using TypeScript, you should import the GridPreferencePanelsValue enum and call showPreferences(GridPreferencePanelsValue.columns). With plain JavaScript you can call showPreferences("columns").


To do this inside of the grid context, for example in a custom Toobar component, you will use the useGridApiContext hook to access the function.

import * as React from "react";
import { Button } from "@mui/material";
import {
  GridToolbarContainer,
  GridPreferencePanelsValue,
  useGridApiContext
} from "@mui/x-data-grid";

export const CustomToolbar = () => {
  const apiRef = useGridApiContext();

  const handleClick = () => {
    apiRef.current?.showPreferences(GridPreferencePanelsValue.columns);
  };

  return (
    <GridToolbarContainer>
      <Button onClick={handleClick}>Show Columns</Button>
    </GridToolbarContainer>
  );
};
<DataGrid
  components={{
    Toolbar: CustomToolbar
  }}
  // your other props
/>

Code Sandbox demo


In order to place your button outside of the grid itself, you need to use the useGridApiRef hook (Pro-only feature). This creates a ref which you will pass to the DataGrid but also allows you to use that ref in your parent component.

Docs: use it outside the grid

import * as React from "react";
import { Box, Button } from "@mui/material";
import {
  DataGridPro,
  GridPreferencePanelsValue,
  useGridApiRef
} from "@mui/x-data-grid-pro";

export const ParentComponent = () => {
  const apiRef = useGridApiRef();

  const handleClick = () => {
    apiRef.current?.showPreferences(GridPreferencePanelsValue.columns);
  };

  return (
    <Box>
      <Button onClick={handleClick}>Show Columns</Button>
      <Box sx={{ height: 400, width: "100%" }}>
        <DataGridPro
          apiRef={apiRef}
          // your other props
        />
      </Box>
    </Box>
  );
}

Code Sandbox demo

There are certainly some workarounds which can avoid the use of the pro-only hook, but this is the cleanest way.

Upvotes: 8

coot3
coot3

Reputation: 632

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>
  );
}

Upvotes: 1

Related Questions