Material-ui: [Table] Set table column width

Created on 19 Oct 2015  ·  54Comments  ·  Source: mui-org/material-ui

Is it possible to set the width of Table columns?

DataGrid question

Most helpful comment

In my vanilla HTML table, the columns width are automatically set depending on content. material-ui seems to enforce equal width on all columns. Is there a way to set width of column to be dynamic instead, like vanilla HTML tables?

All 54 comments

+1

Nothing quite special about this :

const colWidth {
    width: '2rem'
};

<TableRowColumn style={ colWidth }>
    ...
</TableRowColumn>
<TableRowColumn style={{ width: 100 }}>

doesn't behave too well with TableHeaderColumn

Is there any way to dynamically assign the width of col based on content ?

In my vanilla HTML table, the columns width are automatically set depending on content. material-ui seems to enforce equal width on all columns. Is there a way to set width of column to be dynamic instead, like vanilla HTML tables?

@sanfilippopablo, <Table> uses the table-layout: 'fixed' css prop, leading to all columns having the same width, combined with white-space: 'nowrap' on every table cell to handle the overflow.

You can't safely switch to table-layout: 'auto' since the table then grows infinitely with its content unless you remove the above-mentioned white-space css prop. And if you do this,
you can't use the fixedHeader={true} prop anymore since headers are then contained in a separate table :cry:.

Some feedback would be appreciated.

What I've been doing to set the widths of columns is for the

style, set table-layout to auto, as mentioned above, then I give widths in percentages to my columns. i.e. width 30% and width 70%. This would be a two-column layout example, with table header columns in first first column rather than in the header..

You can't safely switch to table-layout: 'auto' since the table then grows infinitely with its content

What about adjusting table header width when the tableRowColumn width changes with content?
I can't seem to set it up so those 2 are aligned.

I guess you either use fixedHeader={true} and can't set a custom width or you don't and have to keep your headers inside your <TableBody>.

Okay, putting header in tbody works! Now I need to figure out how to do multi-line header columns. Any tips?

Are you trying to achieve something like this? (if not, you can probably find the right example in this website)

I think you can do pretty much everything you want with the attributes colSpan on TableHeaderColumn and TableRowColumn and rowSpan on TableRow.

I don't understand - why is this closed?

Putting TableHeader in TableBody doesn't work for me.

@tvtri96
What we suggested was putting tableRow acting as tableheader in tableBody,
but it looks to me like it is now working fine.

this is how it looks now in my code:

<Table fixedHeader={true}>
          <TableHeader>
            <TableHeaderComponent schema={schema}/>
          </TableHeader>
          <TableBody displayRowCheckbox={false} showRowHover={true}>
            {this.props.data.map((item, index) => (
              <TableRowComponent key={index} schema={this.props.schema}
                item={item} onRemoveClick={this.handleRemoveItem}
                onEditClick={this.handleEditItem}
              />
            ))}
          </TableBody>
</Table>

and header columns are aligned with body columns correctly.

Tks for answering me. What is inside TableHeaderComponent? I guess it is not like a normal TableHeader right?
```

Timestamp

Yes, its just wrapped for reasons.

Any news on this? How can I let the columns auto-adjust to content?

This works for me, auto-sizing:

      <Table style={{tableLayout: 'auto'}}>

@arjan

 <Table style={{tableLayout: 'auto'}}>

This has no effect on header.

<Table fixedHeader={false} style={{ tableLayout: 'auto' }}> works (dynamic sizing based on content).

I needed to add width: "auto", which results in:

<Table fixedHeader={false} style={{ width: "auto", tableLayout: "auto" }}>

@nathanmarks, Please reopen.

Table should have a built-in property to allow it to auto-size to contents, and it should not require disabling fixedHeader. I would go further and say auto-size to contents should be the default behavior.

@devuxer Sorry, but we aren't proactively adding features to the v0.x branch.

@mbrookes, Thanks for letting us know. Are you saying the Table in v1.x solves this issue?

@devuxer I beleive so, it was rewritten from the ground up.

https://material-ui-next.com/demos/tables/

I had a table with three columns, where the first and third columns would always contain a small amount of text. I wanted the second column to take up the bulk of the space so the first and third columns would be pushed to the left and right edges of the table, respectively. This worked for me (using style here as opposed to className for brevity):

<Table style={{ tableLayout: "auto" }} />
<TableRowColumn style={{ width: "10%" }}>{text}</TableRowColumn>
<TableRowColumn style={{ width: "80%" }}>{text}</TableRowColumn>
<TableRowColumn style={{ width: "10%" }}>{text</TableRowColumn>

I found a better solution... so, every column has the same width.
Let's say I have three colums, and I want the first one to take up half of the overall width, and the third should be about one third of the row; the one in the middle be the smallest one:

  <TableRowColumn colSpan='3'>twice as big!</TableRowColumn>
  <TableRowColumn> I'm small</TableRowColumn>
  <TableRowColumn colSpan='2'>I'm in between</TableRowColumn>

Actually, I have 7 columns, but the sum of my colspans equals 20 - the last one only holds an icon for deletion, most of the other ones are colspan 3 - the large text field is colspan 6, and a selectfield and a datepicker are on colspan 2...

Works like a charm!

This is good to go in v1.4.3

const styles = { 
    narrowCell: {
        'width': '150px',
    }
};

<Table>
    <TableHead>
        <TableRow>
            <TableCell>Company Name</TableCell>
            <TableCell className={classes.narrowCell} numeric>Amount</TableCell>
        </TableRow>
    </TableHead>
    <TableBody>
    <TableRow>
        <TableCell> name 1 </TableCell>
        <TableCell className={classes.narrowCell}> $100 </TableCell>
    </TableRow>
    </TableBody>
</Table>


Can also give percentage widths, rest of the cells span equally

How can I use this solution if I have to use colspan={2} in a TableHead row?

If I add colspan={2} all cols will have the same width. Something like this:

const styles = { 
    narrowCell: {
        'width': '150px',
    },
    miniCell: {
        'width': '75px',
    },
};

<Table>
    <TableHead>
        <TableRow>
            <TableCell>Company Name</TableCell>
            <TableCell className={classes.narrowCell} numeric colspan={2}>Amounts</TableCell>
        </TableRow>
    </TableHead>
    <TableBody>
    <TableRow>
        <TableCell> name 1 </TableCell>
        <TableCell className={classes.miniCell}> $100 </TableCell>
        <TableCell className={classes.miniCell}> $100 </TableCell>
    </TableRow>
    </TableBody>
</Table>

@Bowfish If you want to change colspan={2} cell width try changing the table width, given it spans the whole table. Smaller cells can be adjusted individually.

Applying this style somehow helped me:
I just sat different maxWidth for different cels in row but same in each column using inline styles.

const styles = (theme) => ({
  tableCell: {
    whiteSpace: 'nowrap',
    overflow: 'hidden',
    textOverflow: 'ellipsis',
    maxWidth: '40px',
  },
});

None of the solutions posted above work. Why is this so difficult to achieve?

  <Table fixedHeader={false} style={{tableLayout: "auto" }}>
        <colgroup>
            <col width="250px" />
            <col />
            <col width="40px" />
            <col width="40px" />
        </colgroup>
        <TableHead>
          <TableRow>

the second collumn is flex

Not sure if anyone is still having an issue with this, but I ended up using withStyles and it worked here's the pseudo Code:

import {withStyles} from '@material-ui/core/styles';  

const styles = theme => ({
    cell: {
        width:'20%'
    },
    cellLarge: {
        width:'60%'
    } 
});

<Table >
       <TableHead>
               <TableRow>
                        <TableCell className={this.props.classes.cell}>header 1</TableCell>
                         <TableCell className={this.props.classes.cell}>header 2</TableCell>
                         <TableCell className={this.props.classes.cellLarge}>header 3</TableCell>
                </TableRow>
          </TableHead>
                <TableBody>
                        <TableRow>
                            <TableCell>value 1</TableCell>
                            <TableCell>value 2</TableCell>
                            <TableCell>value 3</TableCell>
                        </TableRow>
               </TableBody>
   </Table>

export default withStyles(styles)({ComponentName})

None of the solutions posted above work. Why is this so difficult to achieve?

Somehow i recognize why it's not work, because we only set width only forTableHead or TableBody! To make it work, we should define minWidth and maxWidth bot on TableCell in TableHead and TableBody, here the example

<Table>
    <TableHead>
        <TableRow>
            <TableCell column='data1' style={{minWidth:100, maxWidth:100}}>{content}</TableCell>
            <TableCell column='data2' style={{minWidth:'200px', maxWidth:'200px'}}>{content}</TableCell>
        </TableRow>
    </TableHead>
    <TableBody>
            <TableRow>
            <TableCell column='data1' style={{minWidth:100, maxWidth:100}}>{content}</TableCell>
            <TableCell column='data2' style={{minWidth:200, maxWidth:200}}>{content}</TableCell>
            </TableRow>
    </TableBody>
</Table>

As you can see, we can use both value for style by integer and string. But for string, it's only work if you defined it by px, if you use percentage, like minWidth:'25%', it's not gonna work, i already try it.

Why do i use both of minWidth and maxWidth? Not width? Because I already try it, if you want to make your column with fixed width, you must use minWidth and maxWidth instead of width. I didn't know why, but widthseems not work to solve this problem.

Note : _Both of TableCell in TableHead and TableBody that contain same data, must have same style!_

I hope this code help you guys, cheers

I literally set width: 10%, minWidth: 10% and maxWidth: 10% to every single TableCell including the ones under table headers. I then proceeded to create <colgroup>..etc elements and applied the same styles to them as well. i also set the Table element to tableLayout: auto and width: auto. i tried every single solution in this thread and combined them all to this one final output. in addition, i also utilized the "inspect element" tool in chrome and hacked every single element on the table to use width: 10% min-width: 10% and max-width: 10%. this was also reflected in the React inspecter in devtools. it literally showed me all the elements ive changed as "width 10%" etc.

result: still doesnt adjust the widths of columns

i think it is safe to assume now that there is actually an impossible that exists. and it is in this very thread

Edit:

I actually ended up doing something that was against what people in this thread were suggesting... i set autoLayout: fixed in my table and it started working. What in the world is this black magic

Also having a bad time trying to set widths. Had to set the select checkbox width: 0.01% for it to stay at a reasonable width, nothing else works

For those stuck on the old version of this and struggling with the footer, adding fixedFooter={false} to @devenovil 's solution works for me.

@nathanmarks Can you at least clarify why you closed this?
This should be a very recurrent required feature.

@pbassut is right. This is a very basic feature for a table component... Is there any update?
Or an explanation why it is so problematic to implement...

@devenovil Instead of maxWidth, if you want to use %, you can use width like:

<TableCell style={{ width: '35%' }}>
  Table Data
</TableCell>
<TableCell>
  Another Table Data
</TableCell>

For me it worked to set the width only for the cells in the header: <TableCell width={props.colWidths[index] + '%'}>, this results in the columns for the entire table behaving as expected.

I set the column widths with the percentage and it sort of works, but for some reason, it adds a phantom column on the far right. Via inspecting the element, it appears to add a "TableStubCell" element to the table. I have no idea where that came from.

I've had similar issues with other MUI tables, and my work-arounds are never that great. Would be cool if y'all opened up this issue and fixed it...clearly other folks are struggling with it too.

edit: the TableStubCell came from the dx-react-grid-material-ui npm package, so sorry for pointing fingers!

My solution is to do

<Table>
  <TableHeader>
    <TableRow>
      <TableCell>
        <Box width="200px">
          User Fullname
        </Box>
      </TableCell>
      {/* ...rest of the columns */}
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell>
        April Mintac Pineda
      </TableCell>
      {/* ...rest of the columns */}
    </TableRow>
    {/* ...rest of the rows */}
  </TableBody>
</Table>

But would be nice if we could just do

<Table>
  <TableHeader>
    <TableRow>
      <TableCell width="200px">
        User Fullname
      </TableCell>
      {/* ...rest of the columns */}
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell>
        April Mintac Pineda
      </TableCell>
      {/* ...rest of the columns */}
    </TableRow>
    {/* ...rest of the rows */}
  </TableBody>
</Table>

This works for me with the version "@material-ui/core": "4.9.0"

<TableContainer className={classes.container}>
          <Table className={classes.table} stickyHeader size="small">
            <TableHead>
              <TableRow>
                <TableCell width="30%">User Name</TableCell>
                <TableCell width="20%">Designation</TableCell>
                <TableCell width="10%">Nid</TableCell>
                <TableCell width="20%">Email</TableCell>
                <TableCell width="10%">Mobile</TableCell>
                <TableCell width="10%">Gender</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {props.isGridLoading && (
                <TableRow>
                  <TableCell colSpan={6}>
                    <LoadingGridSpinner open={props.isGridLoading} />
                  </TableCell>
                </TableRow>
              )}

              {props.profileObj.lists &&
                props.profileObj.lists.map(row => (
                  <TableRow key={row.userProfileId} hover={true}>
                    <TableCell width="30%">
                      {row.userName}
                    </TableCell>
                    <TableCell width="20%">{row.designation}</TableCell>
                    <TableCell width="10%">{row.nid}</TableCell>
                    <TableCell width="20%">{row.email}</TableCell>
                    <TableCell width="10%">{row.mobile}</TableCell>
                    <TableCell width="10%">{row.gender}</TableCell>
                  </TableRow>
                ))}
            </TableBody>
          </Table>

The approach used by @nazrulcsebd and @crizant worked for me. Here's my code:

<TableContainer component={Paper} style={{ marginTop: 10 }}>
          <Table style={{ width: 'auto', tableLayout: 'auto' }}>
          <TableHead>
            <TableRow>
              <TableCell>Team Member</TableCell>
              <TableCell align="left">Level</TableCell>
              <TableCell align="left">Last Login</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            { tableArray.map(({ id, name, accessLevel, login }) => (
              <TableRow key={id}>
                <TableCell component="th" scope="row" style={{ width: '35%' }}>
                  {name}
                </TableCell>
                <TableCell align="left">{accessLevel}</TableCell>
                <TableCell align="left">{login}</TableCell>
              </TableRow>
            ))
          }
          </TableBody>
        </Table>
      </TableContainer>

In my case I wanted to have the smallest column possible to hold an "action" button at the end of the table. Adding style={{ width: 1 }} to the TableCell in TableHead did the trick.

        <TableContainer component={Paper}>
            <Table className={classes.table} aria-label="simple table">
                <TableHead>
                    <TableRow>
                        {header.map((th, i) => (
                            <TableCell key={i}>{th}</TableCell>
                        ))}
                        <TableCell style={{ width: 1 }}>actions</TableCell>
                    </TableRow>
                </TableHead>
                <TableBody>
                    {data.map((row, i) => (
                        <TableRow key={i} hover>
                            {header.map((h, i) => (
                                <TableCell key={i} align="left">{row[h]}</TableCell>
                            ))}
                            <TableCell>
                                <IconButton aria-label="edit">
                                    <MoreHorizIcon fontSize="small" />
                                </IconButton>
                            </TableCell>
                        </TableRow>
                    ))}
                </TableBody>
            </Table>
        </TableContainer>
const useStyles = makeStyles(theme => ({
  table: {
    "& tr:nth-child(2), & td:nth-child(2) {
      width: '32px',
    }
  }
}));

And then, use the style in the root of the table

 <Table
     ....
     className={classes.table}
>

Haven't tested much yet (Fixed header, etc)

it would be much better if we can just give the same 12 column system to tables for example:

   <TableContainer component={Paper}>
      <Table className={classes.table} aria-label="simple table">
        <TableHead>
          <TableRow>
            <TableCell>Dessert (100g serving)</TableCell>
            <TableCell align="right">Calories</TableCell>
            <TableCell align="right">Fat&nbsp;(g)</TableCell>
            <TableCell align="right">Carbs&nbsp;(g)</TableCell>
            <TableCell align="right">Protein&nbsp;(g)</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map((row) => (
            <TableRow key={row.name}>
              <TableCell component="th" scope="row" xs={4}>
                {row.name}
              </TableCell>
              <TableCell align="right" xs={2}>{row.calories}</TableCell>
              <TableCell align="right" xs={2}>{row.fat}</TableCell>
              <TableCell align="right" xs={2}>{row.carbs}</TableCell>
              <TableCell align="right" xs={2}>{row.protein}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>

Does anyone know a way to let the table scroll in x direction if there are too many columns? I'm only able to make this happen by giving minWidth=something hardcoded (which is not great for unknown number of columns)

It seems like fixedHeader={false} style={{width: "auto", tableLayout: "auto"}} are ignored in the latest version.

Any ideas?

I ended up with a workaround using a list element inside the table, and defining the width of the list item...
Something like:

<TableCell>
  <ul style={{ width: "150px" }}>
    <li>{row.whatever}</li>
    <li>{row.whatever1}</li>
    <li>{row.whatever2}</li>
  </ul>
</TableCell>

2020 and still hard to achieve, the weirdest part is that I try to set the width of a column, the other columns automatically adjust themselves even when I also defined width for them! what gives? It's like the table is making sure the whole table's width doesn't go beyond 100% this is giving me a hard time. If I was not using material-ui's table this would be very very easy, seems material UI only made it hard?

@aprilmintacpineda Did you try with native <table> elements?

@oliviertassinari I did not convert the existing code to native <table> element.

This example works by setting width of all columns
https://codesandbox.io/s/fragrant-framework-oy6uz?file=/src/App.js

Was this page helpful?
0 / 5 - 0 ratings