skip to Main Content

Simply put, I want to create a sidebar on my website that includes a list of items alphabetized from A to Z. I want the items to put within dropdox boxes, such that when you click on A, all of the items that start with A will appear below it.

I’ve gotten the dropdown box working just fine. The problem is that by default all list items are visible. Here’s what I have so far, and this is what I want it to look like by default.

Here’s what I’ve tried.


First of all, the HTML code for this section looks like this.

<li><span>A</span>
</li>
<li><span>B</span>
    <ul>
        <li class="indent">Baldur's Gate</li>
        <li class="indent">Baldur's Gate II: Shadows of Amn</li>
        <li class="indent">Baldur's Gate II: Shadows of Amn (Solo)</li>
        <li class="indent">Baldur’s Gate II: Throne of Bhaal</li>
        <li class="indent">Baldur's Gate III (Livestream)</li>
        <li class="indent">Baldur's Gate: Enhanced Edition</li>
        <li class="indent">Baldur's Gate: Enhanced Edition (Livestream)</li>
        <li class="indent">BioShock Infinite (Livestream)</li>
        <li class="indent">Blood Bowl (Dark Elves)</li>
        <li class="indent">Blood Bowl (Nurgle)</li>
        <li class="indent">Blood Bowl (Skaven)</li>
        <li class="indent">Blood Bowl (Undead)</li>
        <li class="indent">BloodRayne</li>
    </ul>
<li><span>C</span>
    <ul class="indent">
        <li class="indent">Cities Skylines (Livestream)</li>
    </ul>
</li>

Basically, I have a list of items, with each letter of the alphabet as a span. Now I know what you’re thinking: what in the world is class="indent" and why is it in every li? Well, that’s the result of hours of messing about with the code. It’s called indent because I wanted to have every item indented, of course, but I also thought I could add on display: hidden to that class and hide each item by default. That didn’t work. In hindsight I probably need to just add a div wrapped around all of the li and use the indent property that way.

I using class-indent on the ul tag instead. Before we go on, I should note that the code for indent looks like this.

.indent {
    display: none;
    text-indent: 15px;
}

So hid the items, but basically stopped the script that made them appear from working. I suppose I should include that as well.

var allSpan = document.getElementsByTagName('span');

for(var x = 0; x < allSpan.length; x++)
{
    allSpan[x].onclick=function()
    {
        if(this.parentNode)
        {
            var childList = this.parentNode.getElementsByTagName('li');
            for(var y = 0; y< childList.length;y++)
            {
                var currentState = childList[y].style.display;
                if(currentState=="none")
                {
                    childList[y].style.display="block";
                }
                else
                {
                    childList[y].style.display="none";
                }
            }
        }
    }
}

Anyway, I then tried creating a div around the li tags and that did the same thing as above. The items are hidden, but the script no longer works.

I’m pretty much out of ideas. I’d greatly appreciate some help on this one.

3

Answers


  1. Try this way:

    <li><span>A</span>
    </li>
    <li><span>B
    <ul class="indent">
            <li >Baldur's Gate</li>
            <li >Baldur's Gate II: Shadows of Amn</li>
            <li >Baldur's Gate II: Shadows of Amn (Solo)</li>
            <li >Baldur’s Gate II: Throne of Bhaal</li>
            <li >Baldur's Gate III (Livestream)</li>
            <li >Baldur's Gate: Enhanced Edition</li>
            <li >Baldur's Gate: Enhanced Edition (Livestream)</li>
            <li >BioShock Infinite (Livestream)</li>
            <li >Blood Bowl (Dark Elves)</li>
            <li >Blood Bowl (Nurgle)</li>
            <li >Blood Bowl (Skaven)</li>
            <li >Blood Bowl (Undead)</li>
            <li >BloodRayne</li>
        </ul>
    </span>
        
    <li><span>C
     <ul class="indent">
            <li >Cities Skylines (Livestream)</li>
        </ul></span>
       
    </li>
    

    ///////////////////////////////////////////////////////////////////

    var allSpan = document.getElementsByTagName('span');
    
    for(var x = 0; x < allSpan.length; x++)
    {
        allSpan[x].onclick=function(e)
        {
    
            if(this.parentNode)
            {
    
                var childList = e.currentTarget.children;
    
                for(var y = 0; y< childList.length;y++)
                {
                    var currentState = childList[y].style.display;
                    if(currentState=="none")
                    {
                        childList[y].style.display="block";
                    }
                    else
                    {
                        childList[y].style.display="none";
                    }
                }
            }
        }
    }
    

    //////////////////////////////////

    .indent {
        display: none;
        text-indent: 15px;
    }
    
    Login or Signup to reply.
  2. This should fix your problem if I understand your question correctly,

    document.addEventListener('click', function(event) {
      if (event.target.matches('span')) {
        var indentedChild = event.target.nextElementSibling;
    
        if (indentedChild != null && indentedChild.tagName === 'UL') {
          indentedChild.style.display = (indentedChild.style.display === 'block') ? 'none' : 'block';
        }
      }
    });
    .indent {
      display: none;
    }
    <li><span>A</span>
    </li>
    <li><span>B</span>
      <ul class="indent">
        <li>Baldur's Gate</li>
        <li>Baldur's Gate II: Shadows of Amn</li>
        <li>Baldur's Gate II: Shadows of Amn (Solo)</li>
        <li>Baldur’s Gate II: Throne of Bhaal</li>
        <li>Baldur's Gate III (Livestream)</li>
        <li>Baldur's Gate: Enhanced Edition</li>
        <li>Baldur's Gate: Enhanced Edition (Livestream)</li>
        <li>BioShock Infinite (Livestream)</li>
        <li>Blood Bowl (Dark Elves)</li>
        <li>Blood Bowl (Nurgle)</li>
        <li>Blood Bowl (Skaven)</li>
        <li>Blood Bowl (Undead)</li>
        <li>BloodRayne</li>
      </ul>
      <li><span>C</span>
        <ul class="indent">
          <li>Cities Skylines (Livestream)</li>
        </ul>
      </li>

    Hope this will help you 😉

    Login or Signup to reply.
  3. A pure CSS way:

    First, convert A, B, C to <label> elements and add a hidden checkbox inside each. These would be our toggles:

    <label>
      A
      <input type="checkbox">
    </label>
    
    input[type="checkbox"] {
      display: none;
    }
    

    Since nested <ul>s are hidden by default, we will add the following rule as well:

    li > ul {
      display: none;
    }
    

    And this is where magic begins:

    label:has(input[type="checkbox"]:checked) + ul {
      display: block;
    }
    

    The rule above means "show every <ul> that lies next to a label which has a checked checkbox". A <label> element is associated with the <input> inside it, which means if we click it the checkbox will be checked/unchecked as if it was clicked. This rule will override the second one whenever a checkbox is checked.

    Alternatively, you can specify an id for each checkbox so that they can stay outside its corresponding <label> (remember to also add a for attribute to the label):

    <label for="a">A</label>
    <input type="checkbox" id="a">
    

    Try it:

    input[type="checkbox"] {
      display: none;
    }
    
    li > ul {
      display: none;
    }
    
    label:has(input[type="checkbox"]:checked) + ul {
      display: block;
    }
    
    /* Demo only */
    
    label {
      display: block;
      user-select: none;
      cursor: pointer;
    }
    
    label:hover {
      background: #ddd;
    }
    <ul>
      <li>
        <label>
          A
          <input type="checkbox">
        </label>
      </li>
      <li>
        <label>
          B
          <input type="checkbox">
        </label>
        <ul>
          <li>Baldur's Gate</li>
          <li>Baldur's Gate II: Shadows of Amn</li>
          <li>Baldur's Gate II: Shadows of Amn (Solo)</li>
          <li>Baldur’s Gate II: Throne of Bhaal</li>
          <li>Baldur's Gate III (Livestream)</li>
          <li>Baldur's Gate: Enhanced Edition</li>
          <li>Baldur's Gate: Enhanced Edition (Livestream)</li>
          <li>BioShock Infinite (Livestream)</li>
          <li>Blood Bowl (Dark Elves)</li>
          <li>Blood Bowl (Nurgle)</li>
          <li>Blood Bowl (Skaven)</li>
          <li>Blood Bowl (Undead)</li>
          <li>BloodRayne</li>
        </ul>
        <li>
          <label>
            C
            <input type="checkbox">
          </label>
          <ul>
            <li>Cities Skylines (Livestream)</li>
          </ul>
        </li>
    </ul>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search