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:
- 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;
- 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:
- clicking on an item will open its submenu and clicking that item again will hide the submenu
- clicking on an item will hide any visible submenu before to show the submenu child of the clicked item
- 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>
You can see the above code in action here.
That’s all, people. Hope this help 🙂
Hello, this is great, but seems to not work as expected. The children are always displayed and the menu + turns to a – when closed and only then hides the children.
Hi AJ.
That’s strange! Just to be sure I’ve just copied and pasted the published code creating an example and it works as expected. I have added a link to this example at the end of the article but you can just navigate to https://codingfix.com/examples/mgaccordion-example.html and you’ll see that the code just works.
And although I admit that it is not very consistent with what I say in my post, I then turned the code into a plugin that you can find here 😀
Let me know if you get into some issue 🙂 and thank you for reading my blog!