JSFiddle - React, Tailwind, and code Playground
by stitot
HTML
<div>
<table>
<caption>
Table 1: No height (just a regular default table with no extras)
</caption>
<thead>
<tr>
<th>dessert</th>
<th>calories</th>
<th>fat</th>
</tr>
</thead>
<tbody>
<tr>
<td class="outline">Fruit Salad</td>
<td>50</td>
<td>0.3</td>
</tr>
<tr>
<td>Rice Pudding</td>
<td>118</td>
<td class="outline">2</td>
</tr>
<tr>
<td>Custard<br />Line two</td>
<td class="outline">122</td>
<td>3.5</td>
</tr>
<tr>
<td>Bread Pudding</td>
<td>153</td>
<td>4</td>
</tr>
</tbody>
</table>
</div>
<div>
<table class="scroll">
<caption>
Table 2: Height on tbody (add stuff for tbody scroll, but no absolute
positioning etc.)
</caption>
<thead>
<tr>
<th>dessert</th>
<th>calories</th>
<th>fat</th>
</tr>
</thead>
<tbody style="height: 150px">
<tr>
<td class="outline">Fruit Salad</td>
<td>50</td>
<td>0.3</td>
</tr>
<tr>
<td>Rice Pudding</td>
<td>118</td>
<td class="outline">2</td>
</tr>
<tr>
<td>Custard<br />Line two</td>
<td class="outline">122</td>
<td>3.5</td>
</tr>
<tr>
<td>Bread Pudding</td>
<td>153</td>
<td>4</td>
</tr>
<tr>
<td class="outline">Fruit Salad</td>
<td>50</td>
<td>0.3</td>
</tr>
<tr>
<td>Rice Pudding</td>
<td>118</td>
<td class="outline">2</td>
</tr>
<tr>
<td>Custard</td>
<td class="outsline">122</td>
<td>3.5</td>
</tr>
<tr>
<td>Bread Pudding</td>
<td>153</td>
<td>4</td>
</tr>
<tr>
<td class="outline">Fruit Salad</td>
<td>50</td>
<td>0.3</td>
</tr>
<tr>
...
CSS
@import url("https://code.highcharts.com/css/highcharts.css"); /* For colors only */
:root {
/* Fiddle around with these (and hit Run!) to see changes */
--table-border: 1px;
--column-border: 1px;
--row-border: 1px;
--inset: 1px; /* We recommend inset for hightlight borders to avoid content shifting. */
--padding: 8px;
--border-spacing: 0px; /* This is the big one, allowing for more "decorative" tables. */
--cell-border-radius: 0px; /* Best suited if border-spacing > 0. We need for <table> as well. */
}
div {
margin: 20px;
}
table {
box-sizing: border-box;
width: 100%;
border-collapse: separate;
border-spacing: var(--border-spacing);
font-family: Helvetica, Arial, sans-serif;
table-layout: fixed;
color: var(--highcharts-neutral-color-100);
border: var(--table-border) solid var(--highcharts-neutral-color-20);
}
table thead {
background-color: var(--highcharts-neutral-color-5);
}
table th,
table td {
border-radius: var(--cell-border-radius);
box-sizing: border-box;
padding: var(--padding);
border-bottom: var(--row-border, var(--table-border)) solid
var(--highcharts-neutral-color-20);
border-right: var(--column-border, var(--table-border)) solid
var(--highcharts-neutral-color-20);
border-left: clamp(
0px,
var(--border-spacing, 0px),
var(--column-border, var(--table-border))
)
solid var(--highcharts-neutral-color-20);
border-top: clamp(
0px,
var(--border-spacing, 0px),
var(--row-border, var(--table-border))
)
solid var(--highcharts-neutral-color-20);
}
/* The above and below clamp() stuff inserts top and left border only if --border-spacing > 0px, 'cause that looks better. If user disagrees they can override entire selector. */
table tr:last-of-type td {
border-bottom-width: clamp(
0px,
var(--border-spacing, 0px),
var(--row-border, var(--table-border))
);
}
table tr th:last-of-type,
table tr td:last-of-type {
border-right-width:...
JavaScript
document.addEventListener("DOMContentLoaded", function () {
const tables = document.querySelectorAll("table")
tables.forEach((table, index) => {
// This borderSpacing could probably be more slick, but for PoC only
const computedStyle = window.getComputedStyle(table)
const borderSpacing = parseFloat(computedStyle.borderSpacing)
if (borderSpacing) table.classList.add("borderSpacing")
if (table.querySelector("tbody").style.height != "") enableScroll(table)
if (table.classList.contains("enableVirtualization"))
enableVirtualization(table)
})
})
function enableScroll(table) {
const computedStyle = window.getComputedStyle(table)
const tableWidth = parseFloat(computedStyle.width)
const borderWidth = parseFloat(computedStyle.borderWidth)
const tbody = table.querySelector("tbody")
tbody.style.width = `${tableWidth - borderWidth * 2}px`
}
function enableVirtualization(table) {
table.classList.replace("scroll", "virtual")
const thead = table.querySelector("thead")
const tbody = table.querySelector("tbody")
const rows = tbody.querySelectorAll("tr")
const ths = thead.querySelectorAll("th")
const computedStyle = window.getComputedStyle(table)
const borderSpacing = parseFloat(computedStyle.borderSpacing) || 0
const thWidths = Array.from(ths)
.map((th) => th.getBoundingClientRect().width + "px")
.join(" ")
let topOffset = 0
rows.forEach((row) => {
row.style.cssText = `
transform: translateY(${topOffset}px);
grid-template-columns: ${thWidths};
`
topOffset += row.getBoundingClientRect().height + borderSpacing
})
}