reactjsnext.jsmaterial-uidatagridmui-x-data-grid

Column header background color changing when scrolling vertically in MUI X Data Grid


I'm working in a React(NextJS) project using Material UI. I have some tables (MUI X Data Grid component) with different background colors in the column headers like this:

enter image description here

My problem is when I scroll horizontally very fast (not slowly but very fast), the color moves 1 space/column, so in the previous image you can see that the column "rank" for example, should be yellow and if I scroll horizontally very fast, it changes to red:

enter image description here

As you can see the colors move 1 space/column, this seems like a Material UI bug to me but I'm not sure...

This is my React component:

import React, { useState, useEffect } from 'react'
import { css } from '@emotion/react'
import PropTypes from 'prop-types'
import { cardCss } from '../CavMortal/grid/Grid'
import { fullHeight } from '../CavMortal/ScoreItem'
import { CardElevation } from '@findep/mf-landings-core'
import Grid from '@material-ui/core/Grid'
import { DataGrid } from '@mui/x-data-grid';
import { splitString} from '../../helpers/splitString'

const customCardCss = css`
  ${cardCss}
  ${fullHeight}

  & [class*="MuiCardContent-root"] {
      ${fullHeight}
  }
`

function TablaSubdireccion({ dataSubdirecciones, headerStyles }) {
  const [columnsName, setColumnsName] = useState([])
  const [rows, setRows] = useState([])

  const getColumns = () => {
    let columns = []
    for(let i = 0; i < dataSubdirecciones.length; i++){
        for(let j = 0; j < dataSubdirecciones[i].datosAgrupadorList.length; j++){
          columns.push({
            field: dataSubdirecciones[i].datosAgrupadorList[j].nombreDato,
            headerName: dataSubdirecciones[i].datosAgrupadorList[j].nombreDato,
            width: 130,
            renderHeader: (params) => (
              <div>
                {
                  splitString(dataSubdirecciones[i].datosAgrupadorList[j].nombreDato).map((word) => (
                    <React.Fragment key={word}>
                      {word}
                      <br />
                    </React.Fragment>
                  ))
                }
              </div>
            ),
          })
        }
    }
    return columns
  }

  const getRows = () => {
    let rows = []
    for (let i = 0; i < dataSubdirecciones.length; i++) {
      let rowData = { id: i }
      for (let j = 0; j < dataSubdirecciones[i].datosAgrupadorList.length; j++) {
        rowData[dataSubdirecciones[i].datosAgrupadorList[j].nombreDato] = dataSubdirecciones[i].datosAgrupadorList[j].valorDato
      }
      rows.push(rowData)
    }
    return rows
  }
  
  useEffect(() => {
    setColumnsName(getColumns())
    setRows(getRows())
  }, [dataSubdirecciones])

    return(
        <Grid item css={css`flex-grow: 1;`}>
          <div style={{ height: 500, width: '99%' }}>
            <CardElevation fullWidth noPadding css={customCardCss}>
              <DataGrid 
                sx={headerStyles}
                rows={getRows()} 
                columns={getColumns()} 
                hideFooterPagination={true}
                hideFooter={true}
                headerHeight={50}
                pageSize={10}
              />
            </CardElevation>
          </div>
        </Grid>
    )
}

TablaSubdireccion.propTypes = {
  dataSubdirecciones: PropTypes.array,
  headerStyles: PropTypes.object,
}

export default TablaSubdireccion

And this is the object headerStyles, which is received as props and contains the colors for every nth child/column:

const MAIN_TABLES_HEADER_STYLES = {
  '& .MuiDataGrid-columnHeaderTitleContainer': {
    lineHeight: 1.5,
  },
  '.MuiDataGrid-columnSeparator': { display: 'none' },
  '&.MuiDataGrid-root': { border: 'none' },
  '& .MuiDataGrid-columnHeader:nth-child(1)': {
    backgroundColor: '#000000',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(2)': {
    backgroundColor: '#000000',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(3)': {
    backgroundColor: '#9e9e9e',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(4)': {
    backgroundColor: '#9e9e9e',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(5)': {
    backgroundColor: '#9e9e9e',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(6)': {
    backgroundColor: '#9e9e9e',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(7)': {
    backgroundColor: '#6f0000',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(8)': {
    backgroundColor: '#0075ad',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(9)': {
    backgroundColor: '#d20000',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(10)': {
    backgroundColor: '#ffd600',
    color: '#000000',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(11)': {
    backgroundColor: '#ffd600',
    color: '#000000',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(12)': {
    backgroundColor: '#ffd600',
    color: '#000000',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(13)': {
    backgroundColor: '#70b7bc',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(14)': {
    backgroundColor: '#70b7bc',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(15)': {
    backgroundColor: '#009f94',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(16)': {
    backgroundColor: '#1e9a00',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(17)': {
    backgroundColor: '#1e9a00',
    color: '#ffffff',
    fontWeight: 'bold',
  },
  '& .MuiDataGrid-columnHeader:nth-child(18)': {
    backgroundColor: '#1e9a00',
    color: '#ffffff',
    fontWeight: 'bold',
  },
}

Does anybody knows why this happens or how to fix it?

Thanks.


Solution

  • Using nth-child styling isn't going to be reliable when horizontal scrolling is in play. The data grid does virtualization of columns when you scroll horizontally, so not all columns are always being rendered which will then throw off the nth-child styling.

    You can see this in action in this extreme example with 30 columns with customized colors on the 3rd and 4th via nth-child CSS selectors: https://codesandbox.io/s/horizontal-scrolling-tlmqeh?file=/demo.tsx.

    In that example the styling is done similar to your CSS:

            <DataGridPro
              sx={{
                "& .MuiDataGrid-columnHeader:nth-child(3)": {
                  backgroundColor: "red",
                  color: "#ffffff",
                  fontWeight: "bold"
                },
                "& .MuiDataGrid-columnHeader:nth-child(4)": {
                  backgroundColor: "purple",
                  color: "#ffffff",
                  fontWeight: "bold"
                }
              }}
              apiRef={apiRef}
              onCellClick={handleCellClick}
              hideFooter
              {...data}
            />
    

    You can fix this by instead using headerClassName in the column definitions as shown in the documentation here: https://mui.com/x/react-data-grid/style/#styling-column-headers.

    Here's a modification of my earlier example that uses headerClassName: https://codesandbox.io/s/horizontal-scrolling-087h4m?file=/demo.tsx

      const { data } = useDemoData({
        dataSet: "Commodity",
        rowLength: 100
      });
      // data.columns[0] is the hidden id column, so data.columns[1] is the column
      // definition for the first visible column.
      data.columns[3].headerClassName = "red-header";
      data.columns[4].headerClassName = "purple-header";
    
    ...
    
            <DataGridPro
              sx={{
                "& .MuiDataGrid-columnHeader.red-header": {
                  backgroundColor: "red",
                  color: "#ffffff",
                  fontWeight: "bold"
                },
                "& .MuiDataGrid-columnHeader.purple-header": {
                  backgroundColor: "purple",
                  color: "#ffffff",
                  fontWeight: "bold"
                }
              }}
              apiRef={apiRef}
              onCellClick={handleCellClick}
              hideFooter
              {...data}
            />