JSFiddle - React, Tailwind, and code Playground
by Jihad Dzikri Waspada
HTML
<div id="app"></div>
SCSS
.wrapper {
overflow: auto;
width: 500px;
height: 250px;
}
.table {
width: 100%;
overflow: visible;
border-collapse: collapse;
transform-style: preserve-3d; // this is the key,
}
th {
text-align: left;
}
th, td {
padding: 5px;
background: white;
}
Babel + JSX
const CELL_FIXED_CLASSNAME = 'fixed'
let ticking = false;
class FixableTable extends React.Component {
el
thead
tds
componentDidMount() {
this.thead = this.el.querySelector('thead')
this.tds = Array.from(this.el.querySelectorAll(`.${CELL_FIXED_CLASSNAME}`))
}
handleWrapperScroll = (e) => {
const x = e.target.scrollLeft
const y = e.target.scrollTop
this.makeFixed(x, y)
// Use Animation Frame
/* if (!ticking) {
requestAnimationFrame(() => {
this.makeFixed(x, y)
ticking = false
})
}
ticking = true */
}
makeFixed = (x, y) => {
// const wrapper: HTMLDivElement = e.target
// Fixed headers
const scrollTop = `translate3d(0, ${y}px, 1px)`
if (this.thead) {
this.thead.style.transform = scrollTop
}
// Fixed Column(s)
const scrollLeft = `translateX(${x}px)`
this.tds.forEach(col => {
col.style.transform = scrollLeft
})
}
renderHeader() {
const { headers = [], columnsFixed = 0 } = this.props;
return (
<thead>
<tr>
{headers.map((header, i) => <th
className={i + 1 <= columnsFixed ? CELL_FIXED_CLASSNAME : ''}
>{header}</th>)}
</tr>
</thead>
)
}
renderData() {
const { data = [], columnsFixed = 0 } = this.props;
return (
<tbody>
{data.map((rows, i) =>
<tr>{rows.map((row, i) =>
<td
className={i + 1 <= columnsFixed ? CELL_FIXED_CLASSNAME : ''}
>{row}</td>)}
</tr>
)}
</tbody>
)
}
render() {
const { classes, children } = this.props
return (
<div ref={el => (this.el = el)} className={classes.wrapper} onScroll={this.handleWrapperScroll}>
<table className={classes.table}>
{this.renderHeader()}
{this.renderData()}
</table>
</div>
)
}
}
React.render(<FixableTable
headers={['Name', 'Age', 'City',...