htmlcsslisteventsdrop-down-menu

Expandable table of contents with buttons


I seek to design an expandable table of contents. The following CSS + HTML displays hidden list items upon clicking a text portion:

CSS:

#droplist, .show {display: none; }  
.hide:focus + .show {display: inline; }
.hide:focus { display: none; }
.hide:focus ~ #droplist { display:block; }

HTML:

<div style="padding-left:40px">
<a href="#">1. Stuff</a><a href="#" class="hide"> [+]</a> <a href="#" class="show">[-]</a>
    <ul id="droplist" style="margin-top: 4px">
        <li><a href="#">1.1 Object 1</a></li>
        <li><a href="#Lnk">1.2 Object 2</a></li>
    </ul>
</div>

This list, however, is limited to a single nest; if I were to expand further from Object 2, I'd need to add additional paddings.

The code below fails to summon the dropdown:

<ul>
<li><a href="#">1. Stuff</a><a href="#" class="hide"> [+]</a> <a href="#" class="show">[-]</a></li>
    <ul id="droplist" style="margin-top: 4px">
        <li><a href="#">1.1 Object 1</a></li>
        <li><a href="#Lnk">1.2 Object 2</a></li>
    </ul>
</ul>

How do I maintain a list format while keeping the 'button' functional? JSFiddle: http://jsfiddle.net/N79nP/463/

Help is appreciated.


Solution

  • Fully-functional expandable, nested table of contents without recycled JavaScript or CSS: http://jsfiddle.net/qszpx1v7/188/

    EDIT 1: Code now supports multiple tables of contents

    EDIT 2: Code now supports multiple sub-sections

    HTML

    <div id='top'><ul><a href="#" style="color:blue">Content</a>
      <button id="aa1" class="tdropbtn" onclick="Tgl(this.id)" style="display:inline;">[+]</button>
      <button id="paa1" class="tdropbtn" onclick="Tgl(this.id)" style="display:none;">[-]</button>
    
      <div id="lvlaa1" class="tdropdown-content">
        <li><a href="#home">1. Home</a></li>
        <li><a href="#about">2. About</a></li>
        <li><a href="#contact">3. Contact</a>
          <button id="aa2" class="tdropbtn" onclick="Tgl(this.id)" style="display:inline;">[+]</button>
          <button id="paa2" class="tdropbtn" onclick="Tgl(this.id)" style="display:none;">[-]</button></li>
    
        <div id="lvlaa2" class="tdropdown-content">
          <li><a href="#home">3.1 Home</a></li>
          <li><a href="#about">3.2 About</a>
            <button id="aa3a" class="tdropbtn" onclick="Tgl(this.id)" style="display:inline;">[+]</button>
            <button id="paa3a" class="tdropbtn" onclick="Tgl(this.id)" style="display:none;">[-]</button></li>
    
          <div id="lvlaa3a" class="tdropdown-content">
            <li><a href="#home">3.2.1 Home</a></li>
            <li><a href="#about">3.2.2 About</a></li>
            <li><a href="#contact">3.2.3 Contact</a></li>
          </div>
          <li><a href="#contact">3.3 Contact</a>
            <button id="aa3b" class="tdropbtn" onclick="Tgl(this.id)" style="display:inline;">[+]</button>
            <button id="paa3b" class="tdropbtn" onclick="Tgl(this.id)" style="display:none;">[-]</button></li>
    
          <div id="lvlaa3b" class="tdropdown-content">
            <li><a href="#home">3.3.1 Home</a></li>
            <li><a href="#about">3.3.2 About</a></li>
            <li><a href="#contact">3.3.3 Contact</a></li>
          </div>
    
        </div>
      </div>
    </ul>
    <ul><a href="#" style="color:blue">Content</a>
      <button id="ab1" class="tdropbtn" onclick="Tgl(this.id)" style="display:inline;">[+]</button>
      <button id="pab1" class="tdropbtn" onclick="Tgl(this.id)" style="display:none;">[-]</button>
    
      <div id="lvlab1" class="tdropdown-content">
        <li><a href="#home">1. Home</a></li>
        <li><a href="#about">2. About</a></li>
        <li><a href="#contact">3. Contact</a>
          <button id="ab2" class="tdropbtn" onclick="Tgl(this.id)" style="display:inline;">[+]</button>
          <button id="pab2" class="tdropbtn" onclick="Tgl(this.id)" style="display:none;">[-]</button></li>
    
        <div id="lvlab2" class="tdropdown-content">
          <li><a href="#home">3.1 Home</a></li>
          <li><a href="#about">3.2 About</a></li>
          <li><a href="#contact">3.3 Contact</a></li>
        </div>
      </div>
    </ul></div>
    

    CSS

    ul {padding-left: 10px;}
    
    li {display: block;padding-left: 25px; padding-top: 2px;}
    
    .dropbtn {background-color: white; color: blue; padding-left: 8px; 
    font-size: 16px; border: none; cursor: pointer;}
    
    .dropdown-content {display: none; position: relative; background-color: white;
      min-width: 160px; overflow: none;}
    
    .dropdown-content a {color: blue; padding: 2px 0px; display: inline;}
    
    .show {display: block;}
    

    JavaScript

    function Tgl(click_id) {
      var x = document.getElementById(click_id);
      var z = click_id.match(/\d+/)[0];
      var y = click_id.match(/[a-z]{2}[0-9]{1,3}[a-z]{0,2}/);
      var w = document.getElementById(y);
      var t = document.getElementById(`p${y}`);
    
      /* If [+] is visible, make it invisible and display [-] - and vice versa*/
      if (click_id.indexOf('p') >= 0) {
        if (x.style.display === "none") {
          x.style.display = "inline";
          w.style.display = "none";
        }
        if (x.style.display === "inline") {
          x.style.display = "none";
          w.style.display = "inline";
        }
      } else {
        if (x.style.display === "none") {
          x.style.display = "inline";
          t.style.display = "none";
        }
        if (x.style.display === "inline") {
          x.style.display = "none";
          t.style.display = "inline";
        }
      }
      /*Toggle dropdown display onclick*/
      document.getElementById(`lvl${y}`).classList.toggle("tshow");
      /*Increment list spacing with each nest*/
      var p = document.getElementById(`lvl${y}`);
      p.style.left = (9 * z) + 'px';
    }