Goal
I'm wanting to create a table with a scrolling body and a sticky header. The table header cell widths need to match their corresponding body column widths.
It's in React, and the Table component contain two separate components (one for the header, and another for the rows in the body). The content of the components will be coming from an outside source, so I can't make any assumptions on the widths of anything. The body of the table will have a lot of rows, so the table header is going to need to be sticky and stay at the top.
Problem
While the widths of the columns in the table body are automatically set, the widths are not automatically set in the table head. The table header widths need to be automatically set based on the contents of the table.
You can see the issue and my test code here: https://codesandbox.io/s/y0jx5rp081
Things to note
You can get the widths of your table cells by querying for them after rendering. To access a React component after rendering, we'll need to use a ref.
constructor(props) {
...
this.bodyRef = React.createRef()
}
Pass it as a prop to the table body.
<tbody
...
ref={this.bodyRef}
>
Then you can access it after rendering in componentDidMount. If you remove, add or edit rows you may want to do it in componentDidUpdate as well (but be careful not to make an infinite loop).
componentDidMount() {
const row = this.bodyRef.current.children[0].children; // Get the children of one <tr>
// the path from this.bodyRef.current to the children you need may vary.
const headerWidths = [];
for (let i = 0; i < row.length; i += 1) {
headerWidths.push(row[i].getBoundingClientRect().width); // Get the rendered width of the element.
}
this.setState({
headerWidths
});
}
Then just use the width values in your state.
constructor(props) {
...
this.state = {
...
headerWidths: []
}
}
...
render() {
return (
...
<th style={{ width: this.state.headerWidths[index] }}>
...
</th>
)
}
Here's a working version of your handy example.
I'm using react-sticky-table because I need an easy way to create a table with a freezable header and columns. You can't set the width of the cell using width
but you can use max-width
and min-width
as a workaround, which is what I'm doing, to set the cell width. E.g.:
React/JS file:
<Cell className='sticky-table-cell'>
...
CSS file:
.sticky-table-cell{
display: table-cell;
min-width: 400px;
max-width: 400px;
white-space: pre-wrap;
}
pre-wrap
makes sure that the text inside the cell breaks according to the available width.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With