CSS grid with expanding cells
HTML
<div id="id_container">
<div id="id_expanding_grid">
<!-- grid items are created using javascript -->
</div>
</div>
CSS
#id_expanding_grid {
display: grid;
grid-template-rows: repeat(4, 1fr);
grid-template-columns: repeat(3, 1fr);
row-gap: 10px;
column-gap: 10px;
background-color: lightgray;
}
#id_container {
max-width: 800px;
}
.xg-cell {
background-color: lightcoral;
}
.xg-header {
background-color: cornflowerblue;
}
.xg-expanded {
background-color: mediumpurple;
}
.xg-clickable {
cursor: pointer;
}
JavaScript
class ExpandingGrid {
constructor(gridId, transition) {
this.transition = transition;
this.grid = document.getElementById(gridId);
this.computedStyle = window.getComputedStyle(this.grid);
this.rowCount = null;
this.columnCount = null;
this.defaults = {};
this.expandedItemSize = {};
this.timer = null;
this.debounceTimeOut = 100; // ms
this.initialize();
}
initialize() {
this.addResizeListener();
this.grid.addEventListener('click', this.toggleExpanded.bind(this)); // or use arrow function to bind 'this': (event) => this.toggleExpanded(event));
this.rowCount = this.computedStyle.gridTemplateRows.split(' ').length;
this.columnCount = this.computedStyle.gridTemplateColumns.split(' ').length;
this.populate();
this.resetGridStyle();
this.updateExpandedItemSize();
}
toggleExpanded(event) {
/* determine correct target even if we clicked on a child element */
let target = event.target.closest('.xg-clickable');
/* expand or collapse */
if (target) {
if (target.classList.contains('xg-expanded')) {
this.collapse();
} else {
this.expand(target);
}
}
}
collapse() {
/* collapse expanded items (reset everything to default) */
for (const item of document.querySelectorAll('.xg-expanded')) {
item.classList.remove('xg-expanded');
}
this.applyDefaults();
}
expand(target) {
/* expand specified grid item */
let index;
let gapSize;
let gapName;
let templateName;
target.classList.add('xg-expanded');
for (const dim of ['row', 'column']) {
index = parseInt(target.getAttribute(`data-${dim}`));
if (index > 1) {
templateName = `grid-template-${dim}s`;
gapName = `${dim}-gap`;
this.grid.style.setProperty(
templateName,
ExpandingGrid.buildExpandedTemplate(
this[dim + 'Count'],
index,
this.expandedItemSize[dim],
...