Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGrid] Dynamic row height #417

Closed
1 task done
ronnyroeller opened this issue Oct 9, 2020 · 53 comments · Fixed by #4859
Closed
1 task done

[DataGrid] Dynamic row height #417

ronnyroeller opened this issue Oct 9, 2020 · 53 comments · Fixed by #4859
Assignees
Labels
component: data grid This is the name of the generic UI component, not the React module! feature: Rendering layout Related to the data grid Rendering engine new feature New feature or request

Comments

@ronnyroeller
Copy link

  • I have searched the issues of this repository and believe that this is not a duplicate.

Summary 💡

I want to show text in one of the cells. Text can have different length and might span multiple lines. Today, data-grid seem to allow only a fixed rowHeight. I'd like to set this to dynamic - so the row is as high as the content requires. Alternatively, for my use case also something like maxRowHeight would work: I would define the maximal height of a row and the grid uses up to the maxRowHeight - but less if there is less content.

Examples 🌈

image

Motivation 🔦

I want to show in one of the columns text that the user entered (or a snippet of it).

@ronnyroeller ronnyroeller added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Oct 9, 2020
@oliviertassinari oliviertassinari added component: data grid This is the name of the generic UI component, not the React module! new feature New feature or request and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Oct 9, 2020
@oliviertassinari
Copy link
Member

oliviertassinari commented Oct 9, 2020

@ronnyroeller thanks for the feature request. It's definitely something we were expecting. We are happy to see it surface :). For the virtualization to work, the grid needs to know the size of all the rows.

Benchmark

@oliviertassinari oliviertassinari changed the title Dynamic rowHeight [DataGrid] Dynamic rowHeight Oct 9, 2020
@ronnyroeller
Copy link
Author

Thanks a lot for the quick reply, @oliviertassinari Very helpful!

Virtualization is indeed a good point. I was wondering if setting the maximal row height could help with this. For example, if one knows that a row can be max twice the "normal height" -> it might still be possible to do the required calculations (although with a bit more slack).

Background:
We're currently exploring if we should move from <Table> to <XGrid> because the API feels so much nicer and it comes with great (upcoming) features. Hence, I'd really appreciate your guidance where you expect to move with this, considering that dynamic row height is a hard requirement for us.
Hence, is your stance more that dynamic row height isn't going to come - or more that it's coming but we might not be able to use virtualization then (or might pay a heavy performance penalty when using virtualization with dynamic row height).

@oliviertassinari
Copy link
Member

@ronnyroeller We will definitely implement variable and dynamic row heights. There are two standard use cases (probably not even advanced). A max-height could work with dynamic row height.

We have no plans to implement a data grid without virtualization.

@oliviertassinari oliviertassinari changed the title [DataGrid] Dynamic rowHeight [DataGrid] Dynamic row height Oct 12, 2020
@balihoo-wwilkins
Copy link

balihoo-wwilkins commented Nov 2, 2020

We managed to implement this with css and it works for us. No need to set row height on the react datagrid element after this:

".MuiDataGrid-row, .MuiDataGrid-root .MuiDataGrid-cell, .rendering-zone": { "max-height": "none !important", }, ".MuiDataGrid-root .MuiDataGrid-window": { position: "relative !important", }, ".MuiDataGrid-root .MuiDataGrid-viewport": { "max-height": "none !important", }, ".MuiDataGrid-root": { height: "auto !important", },

Issue was positioning and max-height. After this, everything is dynamic for row height

@BrentFarese
Copy link

I have used react-virtuoso for virtualization with dynamic row heights. It supports dynamic row heights out-of-the-box. It is a less-popular package than react-virtualized or react-window, which as far as I know don't support dynamic heights. It does the job pretty well.

@oliviertassinari
Copy link
Member

oliviertassinari commented Nov 4, 2020

cc @petyosi 🙃

@ronnyroeller
Copy link
Author

@balihoo-wwilkins Thanks a lot for sharing your workaround! I tried it out but it seems to confuse the scrolling. If there are items that are higher than rowHeight, it's no longer possible to scroll to the last items on the page.
We will migrate back to <Table> for now and then try again <XGrid>/<DataGrid> once there is progress on this ticket.

@ludvigeriksson
Copy link

For the virtualization to work, the grid needs to know the size of all the rows.

@oliviertassinari You could use the approach Apple does with UIKit, and provide an estimated row height. Then you can continuously update the estimated full height of the table to a more correct value as the user scrolls to reveal more rows (which then report their actual heights). That way you don't need to know the size of all rows up front.

@oliviertassinari
Copy link
Member

A possible workaround, a popup shown on hover: https://codesandbox.io/s/expandcelldemo-forked-2owvu?file=/src/renderCellExpand.tsx

Screenshot 2021-02-21 at 01 37 43

I have tried to improve the first version built by @dtassone

@mouadovic22
Copy link

the only workaround found is that:
https://stackoverflow.com/questions/63761910/material-ui-tablecell-cant-force-a-string-to-display-in-a-new-line-like-list-it

@jitendrasaroj93
Copy link

jitendrasaroj93 commented May 13, 2021

i found the workaround with CSS as

MuiDataGrid-viewport,.MuiDataGrid-row,.MuiDataGrid-renderingZone{
max-height: fit-content!important;
}
.MuiDataGrid-cell{
max-height:fit-content!important;
overflow:auto;
max-height: inherit;
white-space: initial!important;
line-height:16px!important;
display:flex!important;
align-items: center;
padding-top: 10px!important;
padding-bottom: 10px!important;
>div{ //this is for renderCell component wrapped in div
max-height: inherit;
width: 100%;
white-space: initial;
line-height:16px;
}
}

And virtualization works as well as usual.

@hmaack
Copy link

hmaack commented May 20, 2021

A possible workaround, a popup shown on hover: https://codesandbox.io/s/expandcelldemo-forked-2owvu?file=/src/renderCellExpand.tsx

I have tried to improve the first version built by @dtassone

Thanks @oliviertassinari - I forked your approach for another UX - https://codesandbox.io/s/expandcelldemo-forked-rs0hx?file=/src/renderCellExpand.tsx - maybe it's helping someone ( https://rs0hx.csb.app/# )

Screenshot 2021-05-20 at 09 12 05

@JacobMGEvans
Copy link

A possible workaround, a popup shown on hover: https://codesandbox.io/s/expandcelldemo-forked-2owvu?file=/src/renderCellExpand.tsx

Screenshot 2021-02-21 at 01 37 43

I have tried to improve the first version built by @dtassone

I feel like this should be part of the API for the DataGrid

@rafacepsa
Copy link

A possible workaround, a popup shown on hover: https://codesandbox.io/s/expandcelldemo-forked-2owvu?file=/src/renderCellExpand.tsx

Screenshot 2021-02-21 at 01 37 43

I have tried to improve the first version built by @dtassone

Is there a way to edit that component the same way you edit a normal string cell? Currently you can't edit the cell once it reaches the popup state.

@porkupan
Copy link

porkupan commented Feb 5, 2022

.MuiDataGrid-viewport,
.MuiDataGrid-row,
.MuiDataGrid-renderingZone {
    max-height: fit-content !important;
}

The CSS fix doesn't seem to work on Safari (iPhone or Mac). The rows end up broken, with different cells somehow getting different height. Works well for Chrome and Firefox... max-heght: none seems to work on Chrome, Firefox and Safari.

.MuiDataGrid-viewport,
.MuiDataGrid-row,
.MuiDataGrid-renderingZone {
  max-height: none !important;
}

.MuiDataGrid-cell {
  max-height: none !important;
  overflow: auto;
  white-space: initial !important;
  line-height: 16px !important;
  display: flex !important;
  align-items: center;
  padding-top: 10px !important;
  padding-bottom: 10px !important;
}

@blazinaj
Copy link

Just wanted to mention that this CSS from above *mostly works for me. But doesn't work with Column Pinning. The cells in the Pinned Column take on their own height which breaks the whole grid

/* Allows the MUI grid rows to expand to child height */
.MuiDataGrid-viewport,
.MuiDataGrid-row,
.MuiDataGrid-renderingZone {
  max-height: fit-content !important;
}

/* Allows the MUI grid rows to expand to child height */
.MuiDataGrid-cell {
  max-height: fit-content !important;
  overflow: auto;
  white-space: initial !important;
  line-height: 16px !important;
  display: flex !important;
  align-items: center;
  padding-top: 10px !important;
  padding-bottom: 10px !important;
}

image

@m4theushw m4theushw self-assigned this Apr 8, 2022
@m4theushw m4theushw added this to Future in MUI X public roadmap Apr 20, 2022
@joserodolfofreitas joserodolfofreitas moved this from Future to Q2 2022 Apr - Jun in MUI X public roadmap Apr 25, 2022
@roman-kuleshov
Copy link

@blazinaj Did you find any workaround for pinned columns?

@m4theushw
Copy link
Member

Hey all, we're working in adding support for row height based on the content in #4859. We would love to have feedback from the community on how to make this feature perfect.

Documentation: https://deploy-preview-4859--material-ui-x.netlify.app/x/react-data-grid/rows/#dynamic-row-height

@d-s-i
Copy link

d-s-i commented May 22, 2022

I am getting this error Type '() => string' is not assignable to type '(params: GridRowHeightParams) => GridRowHeightReturnValue'. Type 'string' is not assignable to type 'GridRowHeightReturnValue'. with my code and the default code.

My code :

import * as React from "react";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import { TypographyColor } from "../../utils/constants";

interface CustomizedDataGridProps {
rows: { id: number, name: string, to: string, calldata: any }[];
columns: GridColDef[]
rowHeight: number
}

export function CustomizedDataGrid(props: CustomizedDataGridProps) {

return (
  <span onClick={(event: any) => event.stopPropagation()} style={{ width: "100%" }}>
    <DataGrid
      rows={props.rows}
      columns={props.columns}
      disableSelectionOnClick
      sx={{ color: TypographyColor }}
      autoHeight
      hideFooter
      rowHeight={props.rowHeight}
      getRowHeight={() => 'auto'}
    />
  </span>
);
}

Default code: https://deploy-preview-4859--material-ui-x.netlify.app/x/react-data-grid/rows/#dynamic-row-height

@flaviendelangle
Copy link
Member

@d-s-i are you able to reproduce it in a codesandbox with your TS config ?

The following should work, but I would have expected TS to work without the explicit casting

      getRowHeight={() => 'auto' as const}

@AhenkEU
Copy link

AhenkEU commented May 25, 2022

I'm trying to use the new dynamic row height functionality in Material UI. When I add the line "getRowHeight={() => 'auto'}" as mentioned here, I get the warning in the console and grid is not displayed properly. There are missing rows and dynamic row height does not work. I understand that I'm passing a string where there should be a number but I can't find where or how. If I comment the line "getRowHeight={() => 'auto'}", no warnings and works normally but no dynamic row height of course. My code and warnings are below.

Failed prop type: Invalid prop rowHeight of type string supplied to GridRow, expected number.
Failed prop type: Invalid prop height of type string supplied to GridCell, expected number.
NaN is an invalid value for the height css style property.

My code is:

`import {useState} from 'react'
import React from 'react'
import { DataGrid, GridToolbarExport, GridToolbarContainer } from '@mui/x-data-grid'


    function ExportButton() { //CSV Export button 
        return (
          <GridToolbarContainer>
            <GridToolbarExport />
          </GridToolbarContainer>
        );
      }
      

export default function projectsPage() {

    const [projects, setProjects] = useState([])
  
        const fetchProjects = async () =>{
        const response = await fetch('/api/projects')
        const data = await response.json()
        setProjects(data)
        // console.log(data) just to check we receive the data correctly.
    }

    const columns = [
        {field: "id", headerName: "Project ID", width:100},
        {field: "owner", headerName:"Owner ID", width: 100},
        {field: "projectname", headerName:"Project Name", width: 100}
       

    ];

    const rows = projects.map((project)=>({
        id: project._id,
        owner: project.owner,
        projectname: project.projectname
    }))

    

    return (
        <>
      <button onClick={fetchProjects}> Load Projects </button>
        {    
             <div style={{ height:400, width: 900}}>
                    <DataGrid   // Creating datagrid.
                    rows={rows}
                    columns={columns}
                    getRowHeight={() => "auto"}
            
                    sx={{
                    '& .MuiDataGrid-cell': {
                    py: '8px',
                    },
                    }}
                    

                   components={{
                        Toolbar: GridToolbarExport}}
                    options={{  //Adding filtering features
                        filtering:true}}
                                              
                    />

            </div>
            
        }
         </>
    )
    }`

My test data is very basic like this https://i.stack.imgur.com/R6HC3.jpg

@m4theushw
Copy link
Member

@AhenkEU The dynamic row height was not released in the NPM package yet. To experiment with it, you need to use the preview package available by clicking the "Open in CodeSandbox" button in any demo in https://deploy-preview-4859--material-ui-x.netlify.app/x/react-data-grid/rows/#dynamic-row-height

@AhenkEU
Copy link

AhenkEU commented May 25, 2022

@AhenkEU The dynamic row height was not released in the NPM package yet. To experiment with it, you need to use the preview package available by clicking the "Open in CodeSandbox" button in any demo in https://deploy-preview-4859--material-ui-x.netlify.app/x/react-data-grid/rows/#dynamic-row-height

Oh, I thought it is live and useable already. Thank you :)

@krishnagupta21
Copy link

Is it possible to maintain the dynamic row height when editable is enabled on the column. Right now, it compresses to single line input field.

Screen Shot 2022-05-31 at 10 55 15 AM

@m4theushw
Copy link
Member

@krishnagupta21 By default, no. The dynamic row height always uses the row content so it will reduce the height to the height of the <input>. You can try to create a custom edit component using a textarea and add rows=5 to make it taller. However, if you want a built-in solution please upvote #2851

@masull
Copy link

masull commented Jun 1, 2022

Will this support a tree view with pinned columns? Scrolling on expanded grouped rows is a bit janky. The mouse is not always positioned over the scroll bar and it studders a bit when dragging the scroll bar up.
<DataGridPro treeData disableColumnMenu getRowId={(row) => row.Id} rows={rows} columns={columns} getRowHeight={() => "auto"} getTreeDataPath={getTreeDataPath} initialState={{ pinnedColumns: { left: ["__tree_data_group__"] } }} />

Here is another example using the premium grid and grouping. Try expanding a few nodes and scroll down and up.
https://codesandbox.io/s/dynamicrowheightgrid-material-demo-forked-tctdic

@flaviendelangle
Copy link
Member

Indeed there is something wrong with the scrolling there, it stops scrolling from time to time ...

@m4theushw
Copy link
Member

@masull The dynamic row height uses a lazy approach, so it only knows the true height after rendering the row. To calculate the size of the scrollbar, before a row is rendered, we use an estimation. The inconsistency might be explained because the true height is too different from the estimation. You can try to tweak the getEstimatedRowHeight prop to be closer to the final content. The studders is from #5006

@masull
Copy link

masull commented Jun 3, 2022

@masull The dynamic row height uses a lazy approach, so it only knows the true height after rendering the row. To calculate the size of the scrollbar, before a row is rendered, we use an estimation. The inconsistency might be explained because the true height is too different from the estimation. You can try to tweak the getEstimatedRowHeight prop to be closer to the final content. The studders is from #5006

Okay, thanks, I'll give it a try.

@masull
Copy link

masull commented Jun 3, 2022

I have tried various methods, the new, getRowHeight={() => 'auto'} works with pinned columns, but there is a performance penalty when vertically scrolling on say, 30+ treeData rows. The css posted above is promising (performance is fine) except it does not work for pinned columns.

@AkshayG-accruon
Copy link

I have applied this solution, and It worked for me: image image image

You need to set rowHeight to show the sroll bar: image

Fixed . Thanks man

@nozma-knows
Copy link

You can now easily set the row height to dynamically fit the content by adding:

getRowHeight={() => 'auto'}

as a prop to the DataGrid component

Heres a link to the documentation explaining this - https://mui.com/x/react-data-grid/rows/#dynamic-row-height

@namespace-irhad
Copy link

If I am using DataGrid pagination together with autoheight feature is there a way I can prefetch the next page and set the correct height and avoid calling estimatedRowHeight. Right now I can go back to the previous page and there is no flickering since the size is already calculated, I was wondering if the similar case is possible by prefetching the next page with swr for example.

@hassaans208
Copy link

hassaans208 commented Mar 6, 2023

Conflict Resolve

So, for me it worked by using both `getRowHeight` and `rowHeight`, where `getRowHeight `can only be a **string** and `rowHeight `can only be a **number**

When getRowHeight, for some reason, returns null, rowHeight param takes precedence and is used instead!

Read This Document to get have more insight on this issue.

 <DataGrid
                                    getRowId={(obj) => { return obj?._id }}
                                    rows={obj?.tableData?.rows}
                                    columns={obj?.tableData?.columns}
                                    pageSize={obj?.tableData?.pageSize}
                                    rowsPerPageOptions={[obj?.tableData?.rowsPerPageOptions]}
                                    checkboxSelection={props.showCheckbox}
                                    disableSelectionOnClick
                                    getRowHeight={(params) => (props.auto ? 'auto' : null)}
                                    rowHeight={128}
                                    getRowClassName={(params) => `${props.auto ? '' : 'border  border-gray-200 items-center'} py-4 `}
                                />

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: data grid This is the name of the generic UI component, not the React module! feature: Rendering layout Related to the data grid Rendering engine new feature New feature or request
Projects
None yet