<table id="nested">
  <thead><tr><th>123</th><th>456</th><th>789</th></tr></thead>
  <tbody>
    <tr class="parent"><td>1</td><td>1</td><td>1</td></tr>
    <tr class="sub-1"><td>2</td><td>2</td><td>2</td></tr>
    <tr class="parent sub-1"><td>2</td><td>2</td><td>2</td></tr>
    <tr class="sub-2"><td>3</td><td>3</td><td>3</td></tr>
    <tr class="sub-2"><td>3</td><td>3</td><td>3</td></tr>
    <tr class="parent sub-2"><td>3</td><td>3</td><td>3</td></tr>
    <tr class="sub-3"><td>4</td><td>4</td><td>4</td></tr>
    <tr class="sub-2"><td>3</td><td>3</td><td>3</td></tr>
    <tr><td>1</td><td>1</td><td>1</td></tr>
    <tr class="parent"><td>1</td><td>1</td><td>1</td></tr>
    <tr class="sub-1"><td>2</td><td>2</td><td>2</td></tr>
    
  </tbody>
</table>
<br />
<table id="nn">
  <thead><tr><th>123</th><th>456</th><th>789</th></tr></thead>
  <tbody>
    <tr class="pp"><td>1</td><td>1</td><td>1</td></tr>
    <tr class="ss-1"><td>2</td><td>2</td><td>2</td></tr>
    <tr class="pp ss-1"><td>2</td><td>2</td><td>2</td></tr>
    <tr class="ss-2"><td>3</td><td>3</td><td>3</td></tr>
    <tr class="ss-2"><td>3</td><td>3</td><td>3</td></tr>
    <tr class="pp ss-2"><td>3</td><td>3</td><td>3</td></tr>
    <tr class="ss-3"><td>4</td><td>4</td><td>4</td></tr>
    <tr class="ss-2"><td>3</td><td>3</td><td>3</td></tr>
    <tr><td>1</td><td>1</td><td>1</td></tr>
    <tr class="pp"><td>1</td><td>1</td><td>1</td></tr>
    <tr class="ss-1"><td>2</td><td>2</td><td>2</td></tr>  
  </tbody>
</table>
table {
  border: 1px solid black;
  border-collapse: collapse
}
th,td {
  border: 1px solid black;
}

$(window).on('load',function () {
  prepareTableNested('nested','parent','sub');
  prepareTableNested('nn','pp','ss');
})

$('tbody').on('click', 'tr', (el) => {tableNested(el,'parent','sub')}) 
$('tbody').on('click', 'tr', (el) => {tableNested(el,'pp','ss')}) 

function prepareTableNested (nested,parent,sub) {
  $('.'+parent+'').css('cursor','pointer')
  $('[class*="'+sub+'"]').hide()
  $('#'+nested+' thead tr').prepend('<th></th>').css('border','none')
  $('tr.'+parent).css('box-shadow','0 2px 4px rgba(0,0,0,0.35), 0 1px 2px rgba(0,0,0,0.32)')
  tr = $('#'+nested+' tbody')
  tr.children('tr').not('tr.'+parent).prepend('<td style="border:none"> </td>')
  tr.children('tr.'+parent).prepend('<td style="border:none">˅</td>')
}

function tableNested (el,parent,sub) {
  el = $(el.currentTarget)
  let tf,b,a,c
  if (el.hasClass(parent)){
    if (el.is('[class*='+sub+'-]')) {
      tf = true
      b = el.attr('class').split(' ')
      b = parseInt($.grep(b,function(e,n){
        if(e.includes(sub+'-')){return true}
      }).toString().split(sub+'-')[1])
    } else {tf = false}
    if (el.hasClass('show')) {
      el.removeClass('show').children('td:first-child').text(function(index,value){
        return value.replace('˄','˅')
      })
      a = el.next()
      while (a.is('tr') && (!a.is('tr[class*='+parent+']') || a.is('tr[class*='+sub+'-]'))) {
        if (tf) {
          if (a.is('[class*='+sub+'-]')) {
            c = a.attr('class').split(' ')
            c = parseInt($.grep(c,function (el,n) {
              if(el.includes(sub+'-')) {return true}
            }).toString().split(sub+'-')[1])
            if (c>b) {
              if (a.is('[class*='+sub+'-]')) {
                a.hide('fast')
                if (a.hasClass('show')){
                  a.removeClass('show')
                  a.children('td:first-child').text(function(index,value) {
                    return value.replace('˄','˅')
                  })}}}} 
        } else {
          if(a.is('[class*='+sub+'-]')) {
            a.hide('fast')
            if (a.hasClass('show')){
              a.removeClass('show')
              a.children('td:first-child').text(function(index,value) {
                return value.replace('˄','˅')
              })}}}
        a = a.next()
      }
    } else {
      el.addClass('show').children('td:first-child').text(function(index,value){
        return value.replace('˅','˄')
      })
      a = el.next()
      while (a.is('tr') && !a.is('tr[class='+parent+']')) {
        if (tf) {
          if (a.hasClass(sub+'-'+(b+1))){
            a.css('background','rgb('+(210-(b*20))+','+(210)+','+(210-(b*20))+')').show('fast')
          }
          a = a.next()
        } else {
          if (a.hasClass(sub+'-1')){a.css('background','rgb(210,210,210)').show('fast')}
          a = a.next()
        }
      }  
    }
  }
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js