JSFiddle - React, Tailwind, and code Playground

by der_robert

HTML

<table id="table_1" class="table_details">
  <thead>
    <tr>
      <th colspan="2">Row Change</th>
      <th>Feld</th>
      <th>vorher</th>
      <th>nachher</th>
      <th>Datum</th>
      <th>Nutzer</th>
      <th>Aktionen</th> <!-- Neue Spalte -->
    </tr>
  </thead>

  <tbody>
    <tr>
      <td colspan="5">User Action XYZ</td>
      <td>01.01.2000</td>
      <td>Admin</td>
      <td class="actions">
        <button id="show-level-1">A L1</button>
        <button id="show-level-2">A L2</button>
        <button id="show-level-3">A L3</button>
      </td>
    </tr>
  </tbody>

  <tbody class="hidden" data-hide-level="1">
    <tr>
      <td rowspan="8">Aktualisiert 1</td>
      <td rowspan="8">Buchungsoption</td>
      <td></td>
      <td></td>
      <td></td>
      <td rowspan="8"></td>
      <td rowspan="8"></td>
      <td rowspan="8"></td>
    </tr>
    <tr class="hidden" data-hide-level="3">
      <td>Feld 1</td>
      <td>vorher 1</td>
      <td>nachher 1</td>
      <td colspan="2"></td>
    </tr>
    <tr class="hidden" data-hide-level="3">
      <td>Feld 2</td>
      <td>vorher 2</td>
      <td>nachher 2</td>
      <td colspan="2"></td>
    </tr>
    <tr class="hidden" data-hide-level="3">
      <td>Feld 3</td>
      <td>vorher 3</td>
      <td>nachher 3</td>
      <td colspan="2"></td>
    </tr>
    <tr class="hidden" data-hide-level="3">
      <td>Feld 4</td>
      <td>vorher 4</td>
      <td>nachher 4</td>
      <td colspan="2"></td>
    </tr>
    <tr class="hidden" data-hide-level="3">
      <td>Feld 5</td>
      <td>vorher 5</td>
      <td>nachher 5</td>
      <td colspan="2"></td>
    </tr>
    <tr class="hidden" data-hide-level="3">
      <td>Feld 6</td>
      <td>vorher 6</td>
      <td>nachher 6</td>
      <td colspan="2"></td>
    </tr>
    <tr class="hidden" data-hide-level="2">
      <td><strong>Offener Posten</strong></td>
      <td><strong>vorher 1</strong></td>
  ...

CSS

.hidden{
  display: none;
}

JavaScript

function setupHierarchicalToggle(tableId, buttonIds) {
  const table = document.getElementById(tableId);

  function toggleTbodyByLevel(level, visible) {
    table.querySelectorAll(`tbody[data-hide-level="${level}"]`).forEach(tbody => {
      tbody.classList.toggle('hidden', !visible);
      const headerTr = [...tbody.querySelectorAll('tr')].find(tr =>
        tr.querySelector('td')?.hasAttribute('rowspan')
      );
      if (headerTr) headerTr.classList.toggle('hidden', !visible);
    });
  }

  function toggleTrByLevel(level, visible) {
    const trs = table.querySelectorAll(`tr[data-hide-level="${level}"]`);
    const tbodyMap = new Map();

    trs.forEach(tr => {
      if (tr.getAttribute('data-hide-level') === String(level)) {
        tr.classList.toggle('hidden', !visible);

        const tbody = tr.closest('tbody');
        if (!tbodyMap.has(tbody)) {
          tbodyMap.set(tbody, []);
        }
        tbodyMap.get(tbody).push(tr);
      }
    });

    tbodyMap.forEach((trs, tbody) => {
      const anyVisible = trs.some(tr => !tr.classList.contains('hidden'));

      const headerTr = [...tbody.querySelectorAll('tr')].find(tr => {
        const td = tr.querySelector('td');
        return td?.hasAttribute('rowspan') && tr.hasAttribute('data-hide-level');
      });

      if (headerTr) {
        headerTr.classList.toggle('hidden', !anyVisible);
      }
    });
  }

  function isVisible(level) {
    const selector = level === 1
      ? `tbody[data-hide-level="1"]`
      : `tr[data-hide-level="${level}"]`;
    return [...table.querySelectorAll(selector)].some(el => !el.classList.contains('hidden'));
  }

  // Event handlers
  table.querySelector('#'+buttonIds.level1)?.addEventListener('click', () => {
    const l1 = isVisible(1);
    const l2 = isVisible(2);
    const l3 = isVisible(3);

    if (l1 && !l2 && !l3) {
      toggleTbodyByLevel(1, false);
    } else {
      toggleTbodyByLevel(1, true);
   ...