JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.1/css/bootstrap.min.css">
<html>
<body class="bg-danger">
<div class="row h-100 m-0">
<div class="col-4 h-100">
<h3>dummy content</h3>
<ul>
<li>to take</li><li>1/3 of</li><li>screen width</li>
</ul>
</div>
<div class="col h-100">
<div class="root items-nested">
<h3>some dummy content above</h3>
<div class="my-group bg-info-subtle">
<div class="toolbar bg-secondary">
small table:
<label>exp/col<input name="expand" type="checkbox" checked></label>
<label>show<input name="show" type="checkbox" checked></label>
</div>
<div class="tool-body bg-danger-subtle">
<div class="table-wrapper bg-success-subtle">
<table class="my-table table-bordered" style="display: table;">
<tr><th>R \ C</th><th>c1</th><th>c2</th></tr>
<tr><th>r1</th><td>v1</td><td>v2</td></tr>
</table>
</div>
</div>
</div>
<div class="my-group bg-info-subtle">
<div class="toolbar bg-secondary">
wide table:
<label>exp/col<input name="expand" type="checkbox" checked></label>
<label>show<input name="show" type="checkbox"></label>
</div>
<div class="tool-body bg-danger-subtle">
<div class="table-wrapper bg-success-subtle">
<table class="my-table table-bordered" style="display: none;">
<tr>
<th>R \ C</th>
<th>c1-wide</th><th>c2-wide</th><th>c3-wide</th><th>c4-wide</th><th>c5-wide</th>
<th>c6-wide</th><th>c7-wide</th><th>c8-wide</th><th>c9-wide</th><th>c10-wide</th>
</tr>
<tr>
...
CSS
body {
height: 100vh;
}
.root {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
.tool-body {
flex: 1 1 100%;
}
.my-group {
display: contents;
}
.table-wrapper {
display: flex;
width: 100%;
height: 100%;
max-height: 100%;
max-width: 100%;
overflow: auto;
position: relative;
}
.my-table {
margin: auto;
white-space: nowrap;
}
.my-table td {
background-color: var(--bs-body-bg);
}
.my-table th {
background-color: var(--bs-secondary-bg);
}
.my-table tr:first-child {
top: 0;
z-index: 2;
position: sticky;
}
.my-table tr > th:first-child {
left: 0;
z-index: 1;
position: sticky;
}
.my-table tr:first-child > th:first-child {
top: 0;
left: 0;
z-index: 3;
position: sticky;
}
JavaScript
$(document).ready(() => {
$("input[name=expand]").change(function () {
$(this).closest(".my-group").find(".tool-body")
.css("display", $(this).is(":checked") ? "block" : "none");
//refreshAllMaxWidthAndHeight();
//setTimeout(() => refreshAllMaxWidthAndHeight(), 50); //absolute horror to do :(
});
$("input[name=show]").change(function () {
$(this).closest(".my-group").find(".my-table")
.css("display", $(this).is(":checked") ? "table" : "none");
//refreshAllMaxWidthAndHeight();
});
});
function refreshAllMaxWidthAndHeight() {
$(".table-wrapper").each(function() {
refreshMaxWidthAndHeight($(this));
});
}
function refreshMaxWidthAndHeight(wrapper) {
let table = wrapper.find(".my-table");
let prevDisplay = table.css('display');
table.css('display', 'none'); //don't display table so that it doesn't affect parent's width/height
wrapper.css("max-width", "100%"); //undo previously set max-width
wrapper.css("max-height", "100%"); //undo previously set max-height
wrapper.css("max-width", `${wrapper.width()}px`); //whatever width when no table is displayed
wrapper.css("max-height", `${wrapper.height()}px`); //whatever height when no table is displayed
table.css('display', prevDisplay);
}