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.53k stars 1.32k forks source link

[data grid] Easily allow header text to wrap #898

Open iccube-real opened 3 years ago

iccube-real commented 3 years ago

Summary πŸ’‘

Sometimes header titles are too big to fit in one line and we would like to have them in multiple lines.

Ideally, we could have a kind of outfit that is based more on the columns cells width, like Excel, but this one is not trivial. And as the answer might depend on some end users input we do not know in advance either how many rows or size we will get.

Examples 🌈

A very simple example : https://codesandbox.io/s/material-demo-forked-g6ibb

Motivation πŸ”¦

1) Multiple lines for header are sometimes a visually better idea 2) Have a smart resizing that removes the need to manually calculate for each tables column widths and number of lines.

DanailH commented 3 years ago

@iccube-real @oliviertassinari this looks like a duplicate of https://github.com/mui-org/material-ui-x/issues/417 as both are related to multiplies support in cells and since table headers are just a special type of cell it would be appropriate to have that functionality for both when we pick it up.

iccube-real commented 3 years ago

@DanailH , it's the same 'family' yes. You want to fix the maximum number of lines you want manually (height in px is not the point).

Imagine a column that calculates a ranking (it's a small number) but with a bigger title (e.g. 'Developers month ranking'). You don't want your column take too much width but still want to see the whole text of the header -> two lines might look better. After you want ellipsis...

Ideally, it's a competition between the width and the title height to better fit the table that depends on perception (so some users might like more agressive algos than others). Looks for know as a stick in the moon..

Two questions :

_hope it helps.

PS : I'll try to add some images so it's clear

image

oliviertassinari commented 3 years ago

I'm not sure that we should treat this issue as a duplicate of #417. The problem surfaced by @iccube-real seems related be can be solved independently. There is a tension between the width of the columns and the height of the header. It sounds like he should expose the tool required for him to implement his tradeoff.

can we manually set the header with multilines (e.g. 2) for a table?

We don't support it easily right now. I think that it requires simplifying the CSS of the header first, e.g. duplicated white-space: nowrap;. It seems there is quite some noise in the styles. It's should be as straightforward as disabling the no-wrap, if we do such, right now, it's broken: https://codesandbox.io/s/material-demo-forked-y0chb?file=/demo.tsx

Capture d’écran 2021-01-27 aΜ€ 00 37 19

is there a way to calculate the width of column before rendering

The width can be defined for each column definitions. So you can force a specific value. Otherwise, you can listen to update with this private API:

      <DataGrid
        onStateChange={({ state }) => {
          console.log("state", state.columns.lookup.id.width);
        }}

I have renamed the issue to focus on the text wrapping problem. We can only focus on one problem at a time and it seems to be the most relevant one.

giq-re commented 3 years ago

The same issue applies on rows as well. I was able to jerry rig it but it was not pretty. This may be a bigger discussion about being able to more easily override certain styles.

oliviertassinari commented 3 years ago

@giq-re For cells, please see this issue: #417

dtassone commented 3 years ago

One way to do it is to apply a css class on the header and override the MuiDataGrid-colCellTitle

const useStyle = makeStyles({
  root: {
    "& .wrapHeader .MuiDataGrid-colCellTitle": {
      overflow: "hidden",
      lineHeight: "20px",
      whiteSpace: "normal"
    }
  }
});

Check out the full demo https://codesandbox.io/s/header-wrap-text-xzscx?file=/demo.tsx

You can also increase the size of the header row using the headerHeight prop

oliviertassinari commented 3 years ago

@dtassone I think that we should remove the need for using lineHeight: "20px",. Conceptually, I don't see anything that would justify it. It would improve the DX. Also, can't we remove overflow: "hidden", from the codeandbox, the style is already present?

caotrinh commented 3 years ago

How can I just hide the headerName if it is too big to avoid the displaying "Us..." for "User Name"? It looks ugly in the table. Thank you!

Curti-s commented 3 years ago

In ref to this https://github.com/mui-org/material-ui-x/issues/898#issuecomment-785030529

One way to do it is to apply a css class on the header and override the MuiDataGrid-colCellTitle

const useStyle = makeStyles({
  root: {
    "& .wrapHeader .MuiDataGrid-colCellTitle": {
      overflow: "hidden",
      lineHeight: "20px",
      whiteSpace: "normal"
    }
  }
});

Check out the full demo https://codesandbox.io/s/header-wrap-text-xzscx?file=/demo.tsx

You can also increase the size of the header row using the headerHeight prop

This was how I was able to do it

const useStyles = makeStyles({
  root: {
    "& .MuiDataGrid-columnHeaderTitle": {
      overflow: "visible",
      lineHeight: "1.43rem",
      whiteSpace: "normal",
    }
  }
});
iggyzap commented 2 years ago

I was able to find that in @mui/x-data-grid version 5.2.0 result of header being blown out of proportion (https://github.com/mui-org/material-ui-x/issues/898#issuecomment-767906160) is due to lineHeight (translates into line-height css ) being set to 56px which really sets height of the box relative to number of lines text is being broken to. So 56 px with 3 lines of text would be 168 pixels, which blows it out of proportion. Fix? Below:

<DataGrid columns={cols} rows={...} autoHeight={true} headerHeight={80} disableColumnMenu={true} sx={{
            '& .MuiDataGrid-columnHeaderTitle': {
                textOverflow: "clip",
                whiteSpace: "break-spaces",
                lineHeight: 1
            }
        }}>
stamahto commented 2 years ago

Would be great to have auto-height header adjustment if text overflows actual width. I would appreciate it in v6 #3287

john1625b commented 1 year ago

@iggyzap That works for me for most headers but some that are too long get cut off like so: Screenshot 2023-04-05 at 1 05 00 PM

I tried setting headerHeight to be higher but that doesn't fix it.

ryancogswell commented 1 year ago

This came up in StackOverflow: https://stackoverflow.com/questions/75943264/how-to-word-wrap-the-column-from-material-ui-datagrid/75944212#75944212.

Here's the styling I put in my solution there:

      <DataGrid
        sx={{
          "& .MuiDataGrid-columnHeaderTitle": {
            whiteSpace: "normal",
            lineHeight: "normal"
          },
          "& .MuiDataGrid-columnHeader": {
            // Forced to use important since overriding inline styles
            height: "unset !important"
          },
          "& .MuiDataGrid-columnHeaders": {
            // Forced to use important since overriding inline styles
            maxHeight: "168px !important"
          }
        }}

This is similar to what @iggyzap has but also dealing with allowing the height to handle more than 3 rows of text (though after trying this out in my own project, I'm finding issues with the height and maxHeight overrides when using "auto" row height for the data).

rafaelrpd commented 1 year ago

This came up in StackOverflow: https://stackoverflow.com/questions/75943264/how-to-word-wrap-the-column-from-material-ui-datagrid/75944212#75944212.

Here's the styling I put in my solution there:

      <DataGrid
        sx={{
          "& .MuiDataGrid-columnHeaderTitle": {
            whiteSpace: "normal",
            lineHeight: "normal"
          },
          "& .MuiDataGrid-columnHeader": {
            // Forced to use important since overriding inline styles
            height: "unset !important"
          },
          "& .MuiDataGrid-columnHeaders": {
            // Forced to use important since overriding inline styles
            maxHeight: "168px !important"
          }
        }}

This is similar to what @iggyzap has but also dealing with allowing the height to handle more than 3 rows of text.

Yep! It was helping me. Thanks again, @ryancogswell !

We need some kind of feature to do this easily

managervcf commented 1 year ago

Thanks @iggyzap!

However, if I remove the disableColumnMenu={true} prop, left padding of the header is messed up.

To counteract this, I added pl: 1 on the .MuiDataGrid-columnHeader--alignRight .MuiDataGrid-columnHeaderTitleContainer and removed the textOverflow: 'clip'.

<DataGrid
  columns={columns}
  rows={rows}
  autoHeight
  sx={{
    '& .MuiDataGrid-columnHeaderTitle': {
      whiteSpace: 'break-spaces',
      lineHeight: 1,
    },
    '&.MuiDataGrid-root .MuiDataGrid-columnHeader--alignRight .MuiDataGrid-columnHeaderTitleContainer': {
      pl: 1,
    },
  }}
/>;
githorse commented 10 months ago

Baking this feature in would be really helpful. It's really hard to get this right in a way that doesn't screw something else up:

https://github.com/mui/mui-x/assets/8271372/cd54689c-26f2-4af4-a832-8f7093a42d84

For reference, note that AG Grid seems to do this wrapped header thing well.

benosmond commented 2 months ago

We tried implementing this, but we had difficulties getting the header height to adapt to the number of rows of text as the contents wrapped. It would be good to have a native option for this.

scott-gmr commented 1 week ago

The irony of the DataGrid is that for how much it's supposed to do for you with the display of the table, I end up needing to hack its styles constantly to get a reasonably intuitive interface for anything more than a handful of simple columns with short cell values and header names.