JSFiddle - React, Tailwind, and code Playground
by stitot
HTML
<table class="demo-table">
<thead>
<tr>
<!-- LEFT aligned -->
<th class="hcg-th hcg-align-left">
<div class="hcg-header-inner">
<span class="hcg-header-text">Very long left aligned header text</span>
<div class="hcg-header-icons">
<button class="hcg-icon-btn">▲</button>
<button class="hcg-icon-btn">⌕</button>
</div>
</div>
</th>
<!-- CENTER aligned -->
<th class="hcg-th hcg-align-center">
<div class="hcg-header-inner">
<span class="hcg-header-text">Center aligned header text</span>
<div class="hcg-header-icons">
<button class="hcg-icon-btn">i</button>
<button class="hcg-icon-btn">⋮</button>
</div>
</div>
</th>
<!-- RIGHT aligned -->
<th class="hcg-th hcg-align-right">
<div class="hcg-header-inner">
<span class="hcg-header-text">Right aligned numeric header</span>
<div class="hcg-header-icons">
<button class="hcg-icon-btn">⇅</button>
</div>
</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>111</td>
<td>222</td>
<td>333</td>
</tr>
</tbody>
</table>
<script>
document.addEventListener('DOMContentLoaded', function () {
const headers = document.querySelectorAll('.hcg-th');
headers.forEach(th => {
const inner = th.querySelector('.hcg-header-inner');
const icons = th.querySelector('.hcg-header-icons');
const text = th.querySelector('.hcg-header-text');
if (!inner || !icons || !text) return;
function updateCenterMaxWidth() {
if (!th.classList.contains('hcg-align-center')) return;
// Reset before measuring so we get natural text width
text.style.maxWidth = 'none';
const containerWidth = inner.clientWidth;
const iconsWidth =...
CSS
/* --------------------------------------------- */
/* Base table */
/* --------------------------------------------- */
.demo-table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
}
.demo-table th,
.demo-table td {
border: 1px solid #ccc;
padding: 6px 8px;
font-family: system-ui, sans-serif;
font-size: 13px;
}
.hcg-th {
position: relative;
}
/* --------------------------------------------- */
/* Shared header structure */
/* --------------------------------------------- */
.hcg-header-inner {
display: flex;
align-items: center;
width: 100%;
min-width: 0;
gap: 4px;
}
.hcg-header-text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.hcg-header-icons {
display: flex;
align-items: center;
gap: 2px;
}
.hcg-icon-btn {
border: none;
background: transparent;
padding: 2px;
width: 18px;
height: 18px;
cursor: pointer;
font-size: 12px;
border-radius: 4px;
}
.hcg-icon-btn:hover {
background: rgba(0, 0, 0, 0.06);
}
.hcg-icon-btn:focus-visible {
outline: 2px solid #2684ff;
outline-offset: 2px;
}
/* --------------------------------------------- */
/* LEFT aligned */
/* --------------------------------------------- */
.hcg-align-left .hcg-header-inner {
justify-content: flex-start;
}
.hcg-align-left .hcg-header-text {
flex: 1 1 auto;
text-align: left;
}
/* icons slide in by max-width */
.hcg-align-left .hcg-header-icons {
max-width: 0;
opacity: 0;
overflow: hidden;
transition: max-width 0.2s ease, opacity 0.2s ease;
}
.hcg-align-left.hcg-icons-visible .hcg-header-icons {
max-width: 200px; /* big enough for your icons */
opacity: 1;
}
/* --------------------------------------------- */
/* RIGHT aligned */
/*...