JSFiddle - React, Tailwind, and code Playground

by stitot

HTML

<div class="table-wrapper my-theme">
  <table class="my-table">
  <thead>
    <tr>
      <th data-column-id="col-1">Col 1</th>
      <th data-column-id="col-2">Col 2</th>
      <th data-column-id="col-3">Col 3</th>
      <th data-column-id="col-4">Col 4</th>
      <th data-column-id="col-5">Col 5</th>
      <th data-column-id="col-6">Col 6</th>
      <th data-column-id="col-7">Col 7</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td data-column-id="col-1" data-value="1,1">1,1</td>
      <td data-column-id="col-2" data-value="1,2">1,2</td>
      <td data-column-id="col-3" data-value="1,3">1,3</td>
      <td data-column-id="col-4" data-value="1,4">1,4</td>
      <td data-column-id="col-5" data-value="1,5">1,5</td>
      <td data-column-id="col-6" data-value="1,6">1,6</td>
      <td data-column-id="col-7" data-value="1,7">1,7</td>
    </tr>
    <tr>
      <td data-column-id="col-1" data-value="2,1">2,1</td>
      <td data-column-id="col-2" data-value="2,2">2,2</td>
      <td data-column-id="col-3" data-value="2,3">2,3</td>
      <td data-column-id="col-4" data-value="2,4">2,4</td>
      <td data-column-id="col-5" data-value="2,5">2,5</td>
      <td data-column-id="col-6" data-value="2,6">2,6</td>
      <td data-column-id="col-7" data-value="2,7">2,7</td>
    </tr>
    <tr>
      <td data-column-id="col-1" data-value="3,1">3,1</td>
      <td data-column-id="col-2" data-value="3,2">3,2</td>
      <td data-column-id="col-3" data-value="3,3">3,3</td>
      <td data-column-id="col-4" data-value="3,4">3,4</td>
      <td data-column-id="col-5" data-value="3,5">3,5</td>
      <td data-column-id="col-6" data-value="3,6">3,6</td>
      <td data-column-id="col-7" data-value="3,7">3,7</td>
    </tr>
    <tr>
      <td data-column-id="col-1" data-value="4,1">4,1</td>
      <td data-column-id="col-2" data-value="4,2">4,2</td>
      <td data-column-id="col-3" data-value="4,3">4,3</td>
      <td data-column-id="col-4"...

CSS

/* ----------------------------------------------------------
   1) ISOLATION + BASE VARIABLES
------------------------------------------------------------*/
.table-wrapper {
  all: revert;

  --cell-padding: 8px;
  --border-color: #ccc;
}

/*
  Optional theme variables:

  Row:
    --row-bg
    --row-even-bg
    --row-hover-bg

  Column:
    --col-bg
    --col-even-bg
    --col-hover-bg

  Cell:
    --cell-bg
    --cell-hover-bg
    --cell-special-bg

  Text:
    --cell-color
*/

/* ----------------------------------------------------------
   2) TABLE LAYOUT
------------------------------------------------------------*/
.my-table {
  border-collapse: collapse;
  width: 100%;
}

/* Row background (default state) */
.my-table tr {
  --row-bg-current: var(--row-bg, transparent);
}

/* Even rows fallback:
   - If --row-even-bg defined → use it
   - Else → fall back to --row-bg
*/
.my-table tr:nth-child(even) {
  --row-bg-current: var(--row-even-bg, var(--row-bg));
}

/* ----------------------------------------------------------
   COLUMN BACKGROUNDS
------------------------------------------------------------*/
.my-table td {
  /* base: col > transparent */
  --cell-col-bg: var(--col-bg);
}

/* Even columns fallback:
   - If --col-even-bg defined → use it
   - Else → fall back to --col-bg
   (no JS class required)
*/
.my-table td:nth-child(even) {
  --cell-col-bg: var(--col-even-bg, var(--col-bg));
}

.my-table th {
    padding: var(--cell-padding);
    border: 1px solid var(--border-color);  
    text-align: left;  
}

/* ----------------------------------------------------------
   3) NORMAL CELL RENDERING
------------------------------------------------------------*/
.my-table td {
  padding: var(--cell-padding);
  border: 1px solid var(--border-color);

  /* Priority: cell > column > row > transparent */
  background-color: var(
    --cell-bg,
    var(--cell-col-bg,
   ...

JavaScript

document.addEventListener("DOMContentLoaded", function () {
  const wrappers = document.querySelectorAll(".table-wrapper");
  if (!wrappers.length) return;

  wrappers.forEach((wrapper) => {
    const table = wrapper.querySelector(".my-table");
    if (!table) return;

    // --- AUTO-ENABLE HOVER MODES ---
    const cs = getComputedStyle(wrapper);

    const rowHoverVal  = cs.getPropertyValue("--row-hover-bg").trim();
    const colHoverVal  = cs.getPropertyValue("--col-hover-bg").trim();
    const cellHoverVal = cs.getPropertyValue("--cell-hover-bg").trim();

    if (rowHoverVal)  wrapper.classList.add("row-hover-enabled");
    if (colHoverVal)  wrapper.classList.add("col-hover-enabled");
    if (cellHoverVal) wrapper.classList.add("cell-hover-enabled");

    // --- COLUMN HOVER LOGIC ---
    table.addEventListener("mouseover", (event) => {
      const cell = event.target.closest("td, th");
      if (!cell || !table.contains(cell)) return;

      clearColumnHover(table);

      const colIndex = cell.cellIndex;
      if (colIndex < 0) return;

      for (const row of table.rows) {
        const colCell = row.cells[colIndex];
        if (colCell) colCell.classList.add("col-hover");
      }
    });

    table.addEventListener("mouseout", (event) => {
      const cell = event.target.closest("td, th");
      if (!cell || !table.contains(cell)) return;
      clearColumnHover(table);
    });
  });

  function clearColumnHover(table) {
    table.querySelectorAll(".col-hover").forEach((cell) =>
      cell.classList.remove("col-hover")
    );
  }
});