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.52k stars 1.31k forks source link

[data grid] Row css class for striped rows #13218

Closed mauro-ni closed 5 months ago

mauro-ni commented 5 months ago

The problem in depth

Good morning, at https://mui.com/x/react-data-grid/style/#striped-rows you provide a solution to get striped rows. You suggest to use getRowClassName as follows and then to apply the desired style using added classes.

getRowClassName={(params) =>
    params.indexRelativeToCurrentPage % 2 === 0 ? "even" : "odd"
}

Is there a way to automatically get even / odd classes by default? I have around twenty DataGrid instances and I would avoid code repetition.

If I remember correctly, in past versions of mui-x the Mui-even and Mui-odd classes were included automatically. Were they removed for performance reasons?

Many thanks in advance.

Mauro

Your environment

`npx @mui/envinfo` ``` System: OS: macOS 14.5 Binaries: Node: 22.2.0 - /usr/local/bin/node npm: 10.7.0 - /usr/local/bin/npm pnpm: Not Found Browsers: Chrome: 124.0.6367.208 Edge: Not Found Safari: 17.5 npmPackages: @emotion/react: ^11.11.4 => 11.11.4 @emotion/styled: ^11.11.5 => 11.11.5 @mui/base: 5.0.0-beta.44 => 5.0.0-beta.44 @mui/core-downloads-tracker: 5.15.17 @mui/icons-material: 5.15.17 => 5.15.17 @mui/lab: ^5.0.0-alpha.170 => 5.0.0-alpha.170 @mui/material: ^5.15.17 => 5.15.17 @mui/private-theming: 5.15.14 @mui/styled-engine: 5.15.14 @mui/system: ^5.15.15 => 5.15.15 @mui/types: 7.2.14 @mui/utils: 5.15.14 @mui/x-data-grid: 7.5.0 @mui/x-data-grid-premium: ^7.5.0 => 7.5.0 @mui/x-data-grid-pro: 7.5.0 @mui/x-date-pickers: 7.5.0 @mui/x-date-pickers-pro: ^7.5.0 => 7.5.0 @mui/x-license: ^7.2.0 => 7.2.0 @mui/x-tree-view: ^7.5.0 => 7.5.0 @types/react: 18.0.14 react: ^18.3.1 => 18.3.1 react-dom: ^18.3.1 => 18.3.1 typescript: 5.1.6 ```

Search keywords: stripe striped zebra Order ID: 47709

michelengelen commented 5 months ago

No, this is not the only way to do this, just one. You could just as well apply a pure CSS way of doing this.

const StripedDataGrid = styled(DataGridPremium)(({ theme }) => ({
  [`& .${gridClasses.row}:nth-child(even)`]: {
    backgroundColor: theme.palette.grey[200],
    '&:hover': {
      backgroundColor: alpha(theme.palette.primary.main, ODD_OPACITY),
      '@media (hover: none)': {
        backgroundColor: 'transparent',
      },
    },
    '&.Mui-selected': {
      backgroundColor: alpha(
        theme.palette.primary.main,
        ODD_OPACITY + theme.palette.action.selectedOpacity,
      ),
      '&:hover': {
        backgroundColor: alpha(
          theme.palette.primary.main,
          ODD_OPACITY +
          theme.palette.action.selectedOpacity +
          theme.palette.action.hoverOpacity,
        ),
        // Reset on touch devices, it doesn't add specificity
        '@media (hover: none)': {
          backgroundColor: alpha(
            theme.palette.primary.main,
            ODD_OPACITY + theme.palette.action.selectedOpacity,
          ),
        },
      },
    },
  },
}));

You could also do a global override with a custom theme if that is more convenient.

michelengelen commented 5 months ago

notice the [`& .${gridClasses.row}:nth-child(even)/`] CSS selector (nth-child)

flaviendelangle commented 5 months ago

@michelengelen won't that flicker when you scroll due to virtualization?

mauro-ni commented 5 months ago

@michelengelen tanks for your reply. This is exactly the approach I used for a long time, but now with new version 7.50 it flickers and row backgrounds switch.

https://github.com/mui/mui-x/assets/1393996/834195b9-1374-42c4-b5c0-469b36788208

mauro-ni commented 5 months ago

I think it could be useful to define a boolean striped property for DataGrid that automatically adds Mui-even / Mui-odd calsses with default styles when activated. Of course then developers can override and customize the style.

What do you think?

Many thanks, Mauro

flaviendelangle commented 5 months ago

You should be able to set `getRowClassName in your theme so it applies on every data grid you have.

mauro-ni commented 5 months ago

@flaviendelangle how should I put getRowClassName in createTheme({...}) call? Many thanks for your help.

Mauro

mauro-ni commented 5 months ago

Ok, found:

MuiDataGrid: {
    defaultProps: {
        getRowClassName: ({ indexRelativeToCurrentPage }) =>
        indexRelativeToCurrentPage % 2 === 0 ? "even" : "odd",
    },
},
flaviendelangle commented 5 months ago

Here is a working example

It's pretty much what you have in your last message :+1:

mauro-ni commented 5 months ago

@flaviendelangle many thanks for your help!

michelengelen commented 5 months ago

Great that we could be of help and thanks @flaviendelangle for providing a great example. I will close this now, but feel free to reopen if you have follow-up questions! 🙇🏼

github-actions[bot] commented 5 months ago

:warning: This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue. Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

@mauro-ni: How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.

mauro-ni commented 5 months ago

Playing with the new implementation I noticed that on pinned columns the stripe effect is lost.

flaviendelangle commented 5 months ago

@michelengelen can I let you see how to support pinned columns? It's probably just a question of applying the CSS to the right element, unless we don't apply the row classname to pinned columns at all.

mauro-ni commented 5 months ago

@flaviendelangle good morning, regarding the suggested approach for stripes (using alpha), I would like to point out that there is a problem when applying it to pinned columns: on scroll the content this is visible under the pinned columns. It would probably be better to use darken / lighten utilities.

Another styling issue with v 7.5 is on DataGrid used inside Paper component: header and pinned columns get a darker background.

DataGrid-BG

I read about that in https://mui.com/x/migration/migration-data-grid-v6

The column headers and pinned section now require an explicit color. By default, the MUI theme.palette.background.default color will be used. To customize it, see https://mui.com/material-ui/customization/palette/#customization We will be adding a new color name to the palette for additional customization, read #12443 for more details.

Is there a way to globally handle that?

mauro-ni commented 5 months ago

As a temporary solution I managed the background customizing the theme as follows (inPaper is a prop that I set on DataGrid):

MuiDataGrid: {
    styleOverrides: {
        root: ({ ownerState, theme }) => {
            const paperBackground = theme.palette.background.paper;
            if (ownerState?.inPaper) {
                return {
                    [`--DataGrid-pinnedBackground`]: `${paperBackground} !important`,
                    [`--DataGrid-containerBackground`]: `${paperBackground} !important`,
                };
            }
            return {};
        },
    }
}

I don't like this solution, it is a workaround, but ... seems to work.

Do you have a better solution for that?

michelengelen commented 5 months ago

@mauro-ni this seems like a good way to handle the pinned background until we come up with a solid solution internally. Interestingly enough I. haven't noticed the header behavior before. Thanks for pointing that out.

@flaviendelangle I had a codesandbox somewhere where I did implement that once ... just cannot find it anymore! 🤷🏼

But it is rather simple. Instead of targeting the row styles you can just as well target the cells:

`& .${gridClasses.row}.even > .${gridClasses.cell}`
flaviendelangle commented 5 months ago

Maybe we could adapt https://mui.com/x/react-data-grid/style/#striped-rows to handle pinned rows

mauro-ni commented 5 months ago

@michelengelen thank you for your help.

Targeting the cell instead of the row with the code you suggested partially breaks hover effect.

`& .${gridClasses.row}.even > .${gridClasses.cell}`
mauro-ni commented 5 months ago

Here is a temporary solution that, again, I don't like (there was an issue with the implementation with alpha() because pinned columns have forced background, and for now I force the backgrounds I want).

I think that a boolean striped property on DataGrid / DataGridPro / DataGridPremium could be useful (maybe being able to specify hover & selection color).

const ODD_OPACITY = 0.2;

MuiDataGrid: {
    defaultProps: {
      getRowClassName: ({ indexRelativeToCurrentPage }) =>
        indexRelativeToCurrentPage % 2 === 0 ? "even" : "odd",
    },
    styleOverrides: {
      columnHeaderTitle: {
        fontWeight: "bold",
      },
      columnHeader: {
        [`& .MuiFormControl-root`]: {
          flex: 1,
        },
      },
      // HACK to handle DataGrid inside Paper
      root: ({ ownerState, theme }) => {
        const paperBackground = theme.palette.background.paper;
        if (ownerState?.inPaper) {
          return {
            [`--DataGrid-pinnedBackground`]: `${paperBackground} !important`,
            [`--DataGrid-containerBackground`]: `${paperBackground} !important`,
          };
        }
        return {};
      },
      // HACK to make striped rows work with pinned columns
      row: ({ theme }) => ({
        [`&.even, &.even .${gridClasses["cell--pinnedLeft"]}, &.even .${gridClasses["cell--pinnedRight"]}`]:
          {
            backgroundColor:
              theme.palette.mode === "light"
                ? lighten(theme.palette.grey[200], ODD_OPACITY)
                : lighten(theme.palette.grey[900], ODD_OPACITY),
          },
        [`&:hover, &:hover .${gridClasses["cell--pinnedLeft"]}, &:hover .${gridClasses["cell--pinnedRight"]}`]:
          {
            backgroundColor:
              theme.palette.mode === "light"
                ? `rgb(211, 223, 241) !important`
                : `rgb(69, 79, 87) !important`,
            "@media (hover: none)": {
              backgroundColor: "transparent",
            },
          },
        [`&.Mui-selected, &.Mui-selected .${gridClasses["cell--pinnedLeft"]}, &.Mui-selected .${gridClasses["cell--pinnedRight"]}`]:
          {
            backgroundColor:
              theme.palette.mode === "light"
                ? `rgb(196, 213, 237) !important`
                : `rgb(86, 102, 118) !important`,
            [`&:hover, &:hover .${gridClasses["cell--pinnedLeft"]}, &:hover .${gridClasses["cell--pinnedRight"]}`]:
              {
                backgroundColor:
                  theme.palette.mode === "light"
                    ? `rgb(188, 206, 234) !important`
                    : `rgb(96, 115, 134) !important`,
                // Reset on touch devices, it doesn't add specificity
                "@media (hover: none)": {
                  backgroundColor:
                    theme.palette.mode === "light"
                      ? `rgb(196, 213, 237) !important`
                      : `rgb(86, 102, 118) !important`,
                },
              },
          },
      }),
    },
  },
mauro-ni commented 1 month ago

Good evening, is there any update on this? I think it would be nice to have a "striped" property to pass to the DataGrid so that a striped version of the DataGrid is displayed correctly even when placed inside a Paper.

Another question: DataGrid inside a Paper has default background on pinned panel & headers and paper background on rows, is this intentional (see example below)?

https://stackblitz.com/edit/react-f98vax

Many thanks, Mauro