But when I add more items, overflow happens, and you have to scroll page to see bottom elements:
I reproduced problem here: https://codesandbox.io/s/charming-browser-v09uml?file=/src/App.js
Is there any way to solve it better than settings max-height for elements?
export default function Example() {
const items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
return (<div className="root">
<div className="tableHolder">
<div className="header">toolbar</div>
<div className="tableData">
{items.map((item) => {
return (
<div className="item" key={item}>
item
</div>
);
})}
</div>
<div className="footer">pagination</div>
</div>
<div className="expectedSize" />
</div>)
}
.root {
display: flex;
}
.tableHolder {
background-color: darkgray;
width: 600px;
min-height: 400px;
display: flex;
flex-direction: column;
}
.expectedSize {
background-color: lightcoral;
width: 20px;
height: 400px;
}
.header {
height: 50px;
background-color: darkgreen;
}
.footer {
height: 50px;
background-color: yellow;
}
.tableData {
flex-grow: 1;
overflow-y: auto;
}
.item {
height: 60px;
background-color: lightblue;
margin: 10px;
}
Someone else said some helpful things, but they didn't work in my case on a real page. It is caused because this max-height was not applied, any content was getting out of it instead of somehow fitting inside.
I found a solution. Not CSS, unfortunately. I created an additional <div>
element on the place where my table list was, and changed the real table list positioning to fixed and hid it:
<div ref={fillerRef} className={s.positioningElement}/>
<TableContainer style={tablePosition} className={s.tableContainer}>
<!-- Real table internals -->
</TableContainer>
.positioningElement {
pointer-events: none;
flex-grow: 1;
}
In the screenshot, you see this element shown. This <div>
filler has flex-grow: 1
, so it fills all available space between the table header and footer, but since there is nothing inside, it has no limit for minimal space and doesn't have this problem that I had with the original list.
Then I added listeners to the window scroll and resize events, and on these events fired I get the size & position of this filler div, and apply them to the real table list through style.
useEffect(() => {
const updatePosition = () => {
eventBus.emit('update-table-position')
}
window.addEventListener('resize', updatePosition)
window.addEventListener('scroll', updatePosition)
eventBus.emit('update-table-position')
return () => {
window.removeEventListener('resize', updatePosition)
window.removeEventListener('scroll', updatePosition)
}
}, [])
eventBus.on('update-table-position', function () {
const { top, left, height, width } = this.fillerRef.current.getBoundingClientRect()
console.log({ top, left, height, width })
if (height < 50) {
this.setTablePosition({
position: "fixed",
display: "none"
})
} else {
this.setTablePosition({
position: "fixed",
left: `${left}px`,
top: `${top}px`,
height: `${height}px`,
width: `${width}px`,
overflow: `auto`
})
}
this.forceUpdate()
})
Finally, the real table follows the filler <div>
position and size and works just like I expect from it. I also had to add pointer-events: none
to this filler div, to avoid problems with accessing the table in case the <div>
covers it.