The simplest jQuery Accordion ever!

Accordion: what's that?

Accordion, as we all know is an ancient musical instruments used to play folk music in some countries like Italy, Germany...

Okay, I was joking, I like to play. Let's restart.

We all know what an accordion is: an amazing, comfortable way to display a lot of options (usually, menu items) in our html pages without cluttering them.

Here's what Wikipedia says:

The graphical control element accordion is a vertically stacked list of items, such as labels or thumbnails. Each item can be "expanded" or "stretched" to reveal the content associated with that item. There can be zero expanded items, exactly one, or more than one items expanded at a time, depending on the configuration.
The term stems from the musical accordion in which sections of the bellows can be expanded by pulling outward.

An accordion menu lets us to organize our menu items in category and subcategories without any limit, putyting tenths of links in a very small space.

What are you talking about?

Okay, I hear you to say, but why are you telling us all that? We know already...

Well, I know you know and you should know I know you know. The fact is that many peoples , when it comes to play to build an accordion menu start to look for a jQuery plugin: there are a tons around but what I want to show you is that you don't need any plugin to build a fully functional, infinitely extensible Accordion menu: just 11 lines of jQuery (parenthesis included)!

So let me show you a working example of the accordion menu we're going to build together:

Accordion example


[embedit snippet="mg-accordion"]


The simplest accordion menu ever!

Let's start with our Accordion. It will have a couple of great features:

  1. it can be extended as we need without modifying the underlying jQuery code: we can add an infinite number of submenus and items just using a couple of css classes;
  2. every time we'll click on a menu item to show its children we want automatically close any other open menu regardless its level (except of course the one we are in).

The basic markup

So, look at the following markup for our menu. We'll use the element nav to wrap the series of unordered lists that will build menus and submenus. We give to the main list the id "mg-accordion" (you know, mg stays for Marco Gasi 😉 ) Then we'll use class "dropdown" to mark all li elements which hold a submenu and the class "submenu" to mark the ul element which represent the submenu hold by the dropdown list item. In the following snippet you can see highlighted all the lines where these classes are used:

<nav>
    <ul id="mg-accordion" role="navigation" class="row">
        <li><a href="#" title="">All Italian Recipes</a></li>
        <li class="dropdown"><a href="#" title="">First courses</a>  
            <ul class="submenu">
                <li><a href="#">All first courses</a></li>    
                <li><a href="#">All pasta's recipes</a></li>    
                <li><a href="#">All rice's recipes</a></li>    
                <li class="dropdown"><a href="#"> Pasta</a>                 
                    <ul class="submenu">
                        <li><a href="#">Carbonara</a></li>    
                        <li><a href="#">Amatriciana</a></li>    
                        <li><a href="#">Al pesto</a></li>    
                        <li><a href="#">Pomodoro e basilico</a></li>    
                    </ul>
                </li>
                <li class="dropdown"><a href="#">Rice</a>                 
                    <ul class="submenu">
                        <li><a href="#">Milanese</a></li>
                        <li><a href="#">With mushrooms</a></li>
                        <li><a href="#">With peas</a></li>
                        <li><a href="#">With sea food</a></li>
                    </ul>
                </li>
            </ul>
        </li>
        <li class="dropdown"><a href="#">Steack</a>  
            <ul class="submenu">
                <li><a href="#">Stroganoff steaks</a></li>    
                <li><a href="#">Steak & chips</a></li>    
                <li><a href="#">Steak in red wine sauce</a></li>    
                <li><a href="#"> Horseradish butter steaks</a></li>
            </ul>
        </li>
        <li class="dropdown"><a href="#">Fishes</a>  
            <ul class="submenu">
                <li><a href="#">Smoky hake, beans & greens</a></li>    
                <li><a href="#">Grilled miso salmon with rice noodles</a></li>    
                <li><a href="#">Coconut fish curry</a></li>    
                <li><a href="#">Seafood tagine</a></li>    
            </ul>
        </li>
        <li class="dropdown"><a href="#">Fruits</a>  
            <ul class="submenu">
                <li><a href="#">Apricots in syrup with rosemary</a></li>    
                <li><a href="#">Black cherries cinnamon</a></li>    
                <li><a href="#">Caramelized pineapple with cream</a></li>    
            </ul>
        </li>
        <li class="dropdown"><a href="#">Desserts</a>  
            <ul class="submenu">
                <li><a href="#">Chocolate pudding</a></li>    
                <li><a href="#">Tuscan chestnut cake</a></li>    
                <li><a href="#">Hazelnut tart with fig jam</a></li>    
            </ul>
        </li>
    </ul>
</nav>    

Keep in mind you can add as many submenus as you need without change a single comma of the jquery code.

Go with jQuery

What we want to do is to convert this simple list in a fully working Accordion menu.

We want three things:

  1. clicking on an item will open its submenu and clicking that item again will hide the submenu
  2. clicking on an item will hide any visible submenu before to show the submenu child of the clicked item
  3. this mechanism must work respect any level of nested submenus (in the sample above we have three)

Let's go to jQuery. First, we need to embed jQuery:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Is document ready?

$(document).ready(function (){

Now we have to attach an event handler to all anchor elements for the list items which have a submenu. We do this in two steps just to make it a bit more clear:

// first we get our accordion menu and we put it in the variable mymenu
var mymenu = $('ul#mg-accordion');
// then we create the variable dropdowns which holds all anchors children of list items of class 
// dropdowns. These anchors are the ones we have to attach the event handler to: clicking on them will how 
// the hidden submenu
var dropdowns = $(mymenu.find('li.dropdown > a'));

And now the accordion code:

dropdowns.on('click', function (e) {
    //prevent default behavior
    e.preventDefault();
    // we are clicking on an anchor within a list item
    // so we find all ul.submenu elements which are
    // children of any list item which stays at the
    // same level of its parent
    var items = $(this).parents().siblings().find('ul.submenu');
    // for each found ul element we do the following
    items.each(function () {
        if ($(this).is(':visible')) {
            $(this).slideUp('slow');
        }
    });
    // show and hide lists
    $(this).siblings('ul.submenu').slideToggle();
});

If you want allow more than one submenu be visible at the same time you can just delete a few lines of code:

var mymenu = $('ul#mg-accordion');
var dropdowns = $(mymenu.find('li.dropdown > a'));
dropdowns.on('click', function (e) {
    e.preventDefault();                             
    $(this).siblings('ul.submenu').slideToggle();
});

Putting it all together!

That's all. You can style it as you prefer and you have no limit but your fantasy! 🙂

Putting it all together we get the following code: this is exactly the same code you can see running above in my small accordion menu example.

As you can see, I have added some code to put a + (plus) and - (minus) signs near to open and closed submenu and to change them accordingly to the user choices. See the comments in the code to learn more about this.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Accordion test</title>
    <style>
      ul{
        list-style-type: none;                          
      }
      li.dropdown > ul{
        display: none;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="row">
        <div class="col-12">
          <nav class="my-menu">
            <ul id="mg-accordion"class="row"> 
              <li><a href="#" title="">All Italian Recipes</a></li>
              <li class="dropdown"><a href="#" title="">First courses</a>  
                <ul class="submenu">
                  <li><a href="#">All first courses</a></li>    
                  <li><a href="#">All pasta's recipes</a></li>    
                  <li><a href="#">All rice's recipes</a></li>    
                  <li class="dropdown"><a href="#"> Pasta</a>                 
                    <ul class="submenu">
                      <li><a href="#">Carbonara</a></li>    
                      <li><a href="#">Amatriciana</a></li>    
                      <li><a href="#">Al pesto</a></li>    
                      <li><a href="#">Pomodoro e basilico</a></li>    
                    </ul>
                  </li>
                  <li class="dropdown"><a href="#">Rice</a>                 
                    <ul class="submenu">
                      <li><a href="#">Milanese</a></li>
                      <li><a href="#">With mushrooms</a></li>
                      <li><a href="#">With peas</a></li>
                      <li><a href="#">With sea food</a></li>
                    </ul>
                  </li>
                </ul>
              </li>
              <li class="dropdown"><a href="#">Steack</a>  
                <ul class="submenu">
                  <li><a href="#">Stroganoff steaks</a></li>    
                  <li><a href="#">Steak & chips</a></li>    
                  <li><a href="#">Steak in red wine sauce</a></li>    
                  <li><a href="#"> Horseradish butter steaks</a></li>
                </ul>
              </li>
              <li class="dropdown"><a href="#">Fishes</a>  
                <ul class="submenu">
                  <li><a href="#">Smoky hake, beans & greens</a></li>    
                  <li><a href="#">Grilled miso salmon with rice noodles</a></li>    
                  <li><a href="#">Coconut fish curry</a></li>    
                  <li><a href="#">Seafood tagine</a></li>    
                </ul>
              </li>
              <li class="dropdown"><a href="#">Fruits</a>  
                <ul class="submenu">
                  <li><a href="accordion.php">Apricots in syrup with rosemary</a></li>    
                  <li><a href="#">Black cherries cinnamon</a></li>    
                  <li><a href="#">Caramelized pineapple with cream</a></li>    
                </ul>
              </li>
              <li class="dropdown"><a href="#">Desserts</a>  
                <ul class="submenu">
                  <li><a href="#">Chocolate pudding</a></li>    
                  <li><a href="#">Tuscan chestnut cake</a></li>    
                  <li><a href="#">Hazelnut tart with fig jam</a></li>    
                  <li class="dropdown"><a href="#">Desserts</a>  
                    <ul class="submenu">
                      <li><a href="#">Chocolate pudding</a></li>    
                      <li><a href="#">Tuscan chestnut cake</a></li>    
                      <li><a href="#">Hazelnut tart with fig jam</a></li>    
                      <li class="dropdown"><a href="#">Desserts</a>  
                        <ul class="submenu">
                          <li><a href="#">Chocolate pudding</a></li>    
                          <li><a href="#">Tuscan chestnut cake</a></li>    
                          <li><a href="#">Hazelnut tart with fig jam</a></li>    
                          <li class="dropdown"><a href="#">Desserts</a>  
                            <ul class="submenu">
                              <li><a href="#">Chocolate pudding</a></li>    
                              <li><a href="#">Tuscan chestnut cake</a></li>    
                              <li><a href="#">Hazelnut tart with fig jam</a></li>    
                            </ul>
                          </li>
                          <li class="dropdown"><a href="#">Desserts</a>  
                            <ul class="submenu">
                              <li><a href="#">Chocolate pudding</a></li>    
                              <li><a href="#">Tuscan chestnut cake</a></li>    
                              <li><a href="#">Hazelnut tart with fig jam</a></li>    
                            </ul>
                          </li>
                        </ul>
                      </li>
                      <li class="dropdown"><a href="#">Desserts</a>  
                        <ul class="submenu">
                          <li><a href="#">Chocolate pudding</a></li>    
                          <li><a href="#">Tuscan chestnut cake</a></li>    
                          <li><a href="#">Hazelnut tart with fig jam</a></li>    
                          <li class="dropdown"><a href="#">Desserts</a>  
                            <ul class="submenu">
                              <li><a href="#">Chocolate pudding</a></li>    
                              <li><a href="#">Tuscan chestnut cake</a></li>    
                              <li><a href="#">Hazelnut tart with fig jam</a></li>    
                            </ul>
                          </li>
                          <li class="dropdown"><a href="#">Desserts</a>  
                            <ul class="submenu">
                              <li><a href="#">Chocolate pudding</a></li>    
                              <li><a href="#">Tuscan chestnut cake</a></li>    
                              <li><a href="#">Hazelnut tart with fig jam</a></li>    
                            </ul>
                          </li>
                        </ul>
                      </li>
                    </ul>
                  </li>
                </ul>
              </li>
            </ul> 
          </nav>        
        </div>
      </div>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script type="text/javascript">
       $(document).ready(function () {
           var mymenu = $('ul#mg-accordion');
           var dropdowns = $(mymenu.find('li.dropdown > a'));
           dropdowns.each(function () {
               $(this).prepend('+ ');//we add a + (plus) symbol to highlight the fact that the node holds a submenu
           });
           dropdowns.on('click', function (e) {
               e.preventDefault();
               //Following 5 lines change the plus/minus symbols accordingly to the submenu state
               if ($(this).text().charAt(0) === '+') {
                   $(this).text($(this).text().replace('+', '-'));
               } else {
                   $(this).text($(this).text().replace('-', '+'));
               }
               var items = $(this).parents().siblings().find('ul.submenu');
               items.each(function () {
                   if ($(this).is(':visible')) {
                       $(this).slideUp('slow');
                       //we update plus/minus symbol in all siblings submenus 
                       $(this).siblings('.dropdown a').text($(this).siblings('.dropdown a').text().replace('-', '+'));
                   }
               });
               $(this).siblings('ul.submenu').slideToggle();
           });
       });
    </script>           
  </body>
</html>

That's all, people. Hope this help 🙂

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.