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.34k stars 1.3k forks source link

[DataGrid] Dynamic row height #417

Closed ronnyroeller closed 2 years ago

ronnyroeller commented 4 years ago

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).

oliviertassinari commented 4 years ago

@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

ronnyroeller commented 4 years ago

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 commented 4 years ago

@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.

balihoo-wwilkins commented 4 years ago

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 commented 3 years ago

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 commented 3 years ago

cc @petyosi 🙃

ronnyroeller commented 3 years ago

@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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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.

m4theushw commented 3 years ago

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.

@rafacepsa Yes, you can create a custom edit component based on the Popover: https://material-ui.com/components/data-grid/editing/#custom-edit-component

However, double-clicking the expandable cell doesn't switch to the edit mode because it's rendered inside a Portal. There're two ways to overcome this problem:

vincent-paing commented 3 years ago

Has this been implemented or is there a workaround for this?

gnowland commented 3 years ago

Has this been implemented or is there a workaround for this?

Hey @vincent-paing, I was able to successfully work around the limitation with the following code (excerpted for brevity):

import React, { Component } from 'react';
import { withStyles } from '@material-ui/styles';
import { XGrid, LicenseInfo } from '@material-ui/x-grid';

...

const styles = theme => ({
  dataGrid: {
    minHeight: '132px',

    '& .MuiDataGrid-dataContainer, & .MuiDataGrid-viewport': {
      minWidth: 'auto!important'
    },

    '& .MuiDataGrid-viewport': {
      width: 'fit-content',
      maxWidth: 'none!important',
      minWidth: '100%!important'
    },

    '& .MuiDataGrid-viewport, & .MuiDataGrid-renderingZone, & .MuiDataGrid-row': {
      maxHeight: 'fit-content!important',
    },

    '& .MuiDataGrid-renderingZone': {
      transform: 'none!important',
      marginRight: '-16px'
    },

    '& .MuiDataGrid-columnHeaderTitle, & .MuiDataGrid-cell': {
      textOverflow: 'unset',
      whiteSpace: 'normal',
      lineHeight: '1.2!important',
      maxHeight: 'fit-content!important',
      minHeight: 'auto!important',
      height: 'auto',
      display: 'flex',
      alignItems: 'center',
      alignSelf: 'stretch',

      '& > div': {
        maxHeight: 'inherit',
        width: '100%',
        whiteSpace: 'initial',
        lineHeight: '1'
      }
    },

    '& .MuiDataGrid-columnHeader > div': {
      height: '100%'
    },

    '& .MuiDataGrid-columnHeaderWrapper': {
      maxHeight: 'none!important',
      flex: '1 0 auto',
    },

    '& .MuiDataGrid-row .MuiDataGrid-columnsContainer': {
      maxHeight: 'none!important'
    },

    '& .MuiDataGrid-cell': {
      overflowWrap: 'anywhere',
      padding: '0',

      '&--textRight div': {
        textAlign: 'right',
        justifyContent: 'flex-end'
      },

      '&:last-of-type > div': {
        paddingRight: theme.spacing(3)
      },

      '& > div': {
        padding: '0.75em',
        display: 'flex',
        alignSelf: 'stretch',
        alignItems: 'center'
      }
    }
  }
});

...

class DataGridComponent extends Component {
  constructor(props) {
    super(props);
  }

  ...

  render() {
    const { classes } = this.props;

    return (
      <XGrid
        className={classes.dataGrid}
        rows={this.state.tableRows}
        columns={this.state.tableColumns}
        columnBuffer={this.state.tableColumns.length || 5}
        autoHeight={false}
        rowHeight={0}
        headerHeight={100}
        scrollbarSize={16}
        disableExtendRowFullWidth={false}
        disableColumnMenu={true}
        disableColumnResize={true}
        disableColumnReorder={true}
        hideFooter={true}
        pagination={false}
        hideFooterPagination={true}
        autoPageSize={false}
      />
    );
  }
}
export default withStyles(styles, {withTheme: true})(DataGridComponent);

NOTE: There may be some unnecessary styles in there (I was modifying the table in a couple different ways, like width), but this should be good enough to get you pointed in the right direction.

Hope this helps! 🌞

oliviertassinari commented 3 years ago

@gnowland autoHeight is in the MIT version, I assume all the developers can rely on this workaround. Thanks for sharing.

cristianocaon commented 3 years ago

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 am trying to implement the workaround provided @oliviertassinari, however I am getting an error saying that 'isOverflown' is not exported from "@material-ui/data-grid"

m4theushw commented 3 years ago

@cristianocaon https://mui.com/components/data-grid/columns/#render-cell for the updated demo.

kguptaaa commented 3 years ago

@cristianocaon https://mui.com/components/data-grid/columns/#render-cell for the updated demo.

still can't see the isOverflown property in the demo. How can we access this property in datagrid-pro?

m4theushw commented 3 years ago

@kguptaaa You have to scroll to "Expand cell renderer".

image
jsmolina commented 3 years ago

We got the cell to grow in height when required to. But, in any case Table height seems to be automatically hard-coded and calculated by the number of shown rows. So, only adding an scrollbar to the table works.

Is it possible to change this behaviour?

flaviendelangle commented 3 years ago

Table height seems to be automatically hard-coded and calculated by the number of shown rows

If you have autoHeight: true yes, the Table takes the height needed to render all the rows But by default it is the other way around. The Table takes the size of its parent and we deduce the amount of row to render based on that height.

Hard coding the height of the Table allows us to virtualize the rendering. Making the virtualization works with dynamic row height is a complicated task. We have planned to spend time on it (thus this issue) but it will probably not be any time soon.

First, we want to achieve #438 where the height of each row can be different, but will not change in time. This is needed for #211 and probably other features and should be easier to achieve.

zehawki commented 3 years ago

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/# )

@hmaack thank you. Certainly helped me. Enhanced it a bit further by removing the Link and replacing with:

          <IconButton aria-label="expand" color="primary" onClick={handleClick}>
            <ExpandMoreIcon />
          </IconButton>

for a clean UI:

image

kh-mubashar commented 2 years ago

'.MuiDataGrid-cell': { wordBreak: 'break-all', maxHeight: 'fit-content!important', overflow: 'auto', whiteSpace: 'initial!important', lineHeight: '16px!important', display: 'flex!important', alignItems: 'center', paddingTop: '10px!important', paddingBottom: '10px!important' }, '.MuiDataGrid-cell div': { maxHeight: 'inherit', width: '100%', whiteSpace: 'initial', lineHeight: '16px' }

i used the following CSS it works for the work with underscore and spaces

LazzyLizzard commented 2 years ago

I have the same problem and I'd like to make the things clear.

Dear @oliviertassinari, @flaviendelangle - are there any plans to fix this issue and if yes, when can we expect resolving this issue?

flaviendelangle commented 2 years ago

@DanailH should be able to release #3218 soon.

What is your use-case for dynamic row height ? (= rows with non-predictable height)

kguptaaa commented 2 years ago

@flaviendelangle I'm also waiting for this fix, my use case is that the data in the cell for a particular column is variable in length. It can have 20 words or 100 words and so I want the row's height to adjust such that the whole text can be viewed (and ideally edited) easily. Right now I'm using the popover solution recommended above, but its really hard to make it work for when editing on the cell is enabled.

phamkimtho commented 2 years ago

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

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

phamkimtho commented 2 years ago

Hi bro, I have not encountered this case, do you have any solution?

Best Regard!

*Tho Pham (Thomas Pham) Phạm Kim Thọ GIS Application Developement Mobile phone: 0907095100 Email: tho.phamkim@ @.**>gmail.com http://gmail.com

Vào Th 5, 6 thg 1, 2022 vào lúc 03:33 kguptaaa @.***> đã viết:

@phamkimtho https://github.com/phamkimtho your solution works. However, do you know how I can maintain the styling when its in edit mode (onCellEditStart) ? I notice that in edit mode the text < span > changes to an < input > and so the styling for the text is lost. As a result, its hard to see the full text at once.

Here's a gif showing the issue: [image: ezgif com-gif-maker] https://user-images.githubusercontent.com/80909021/148285194-4b9e80c6-e9b8-48b5-b6d8-1fa7e97312da.gif

— Reply to this email directly, view it on GitHub https://github.com/mui-org/material-ui-x/issues/417#issuecomment-1006056984, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJF5ITIOLOA5KI226XCUSI3UUSTJZANCNFSM4SKQZIAA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you were mentioned.Message ID: @.***>

vanilton-filho commented 2 years ago
.MuiDataGrid-viewport,
.MuiDataGrid-row,
.MuiDataGrid-renderingZone {
    max-height: fit-content !important;
}

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

Adding this CSS to index.css worked for me, without using any other configuration.

ibrahimhajjaj commented 2 years ago

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/# )

@hmaack thank you. Certainly helped me. Enhanced it a bit further by removing the Link and replacing with:

          <IconButton aria-label="expand" color="primary" onClick={handleClick}>
            <ExpandMoreIcon />
          </IconButton>

for a clean UI:

image

Could you please provide a codesnabox

porkupan commented 2 years ago
.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 commented 2 years ago

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

roman-kuleshov commented 2 years ago

@blazinaj Did you find any workaround for pinned columns?

m4theushw commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

@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 https://github.com/mui/mui-x/issues/2851

masull commented 2 years ago

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 commented 2 years ago

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

m4theushw commented 2 years ago

@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 https://github.com/mui/mui-x/issues/5006

masull commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

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