Saving state with the jQuery Accordion Menu

Saving state with the jQuery Accordion Menu

I have been working on the new True Negative website pretty much non-stop lately and I’m using several differernt things from the jQuery JavaScript library. One of these is the jQuery Accordion Menu, from their User Interface library. It’s a great simple menu that can be implemented with very little javascript code.

One thing that it doesn’t inherently support is saving the state between webpages, which is something I had wanted since I’m using it as a menu, not just for content display. Functionally, I knew what had to be done in order to get it to save state. It was obvious that I needed to use cookies and some quick javascript to save what menu was open. I then came across the jQuery Cookie plugin, which really simplifies working with cookies in jQuery.

Setting a cookie with the plugin is as simple as follows:

$.cookie('cookiename', 'cookiecontents');

The accordion menu has an event change attribute, which can be set to a function or just inline code. Using both this feature and the cookie plugin, it was very simple to write the code that I needed in order to get the result I wanted. Here is the code and I will explain it below:

// accordion menu
$('#menu').accordion({
	header: 'h3',
	navigation: true,
	active: '.selected',
	autoHeight: false,
	clearStyle: true,
	collapsible: true,
	alwaysOpen: false,
	animated: 'slide',
	change: function(event,ui) {
		var hid = ui.newHeader.children('a').attr('id');
	if (hid === undefined) {
		$.cookie('menustate', null);
	} else {
		$.cookie('menustate', hid, { expires: 2 });
	}
}
});

// check cookie for accordion state
if($.cookie('menustate')) {
	$('#menu').accordion('option', 'animated', false);
	$('#menu').accordion('activate', $('#' + $.cookie('menustate')).parent('h3'));
	$('#menu').accordion('option', 'animated', 'slide');
}

The first section is pretty straightforward. It defines and applies the accordion menu to a div tag with an id of menu. All of the various options are laid out in the Accordion docs and I just set some of the standard ones in order to get the look and feel that I wanted. The important part is the change option:

change: function(event,ui) {
		var hid = ui.newHeader.children('a').attr('id');
	if (hid === undefined) {
		$.cookie('menustate', null);
	} else {
		$.cookie('menustate', hid, { expires: 2 });
	}

Here you can see that I check the value of the menu that is open to see if it is undefined, which would mean the menu is closed. If it is open, it will have a value in there, so I store that in a cookie called “menustate” for use when the page is reloaded.

// check cookie for accordion state
if($.cookie('menustate')) {
         $('#menu').accordion('option', 'animated', false);
         $('#menu').accordion('activate', $('#' + $.cookie('menustate')).parent('h3'));
         $('#menu').accordion('option', 'animated', 'slide');

Upon page reload I have it check the “menustate” cookie to see if it has been set or not. If it is, I first turn off the animation so the visitor does not see it open again, then I call the activate method to open the one with the id that is stored in the cookie. Lastly, I reenable the animation. It works great!

Unfortunately, I have no completed the True Negative site yet, so I do not have an example of this working. As soon as I finish the site, I’ll update this blog post with a link to it. Hope this helps anyone trying to do this in a simple way. Thanks for reading!

About The Author

Mike
Mike is an active member and entrepreneur in the firearms and motorsports industries, current President & CEO of Allstar Tactical, adjunct professor at Monroe Community College, as well as contributor to other blogs and publications. When not active in his various entrepreneurial ventures, Mike is involved in several hobbies including, electronic music, radio controlled vehicles, riding motorcycles, watches, fitness, family and causing his wife grief.

32 Comments

  • drewho on July 3, 2009

    cheers for this, saved my bacon

    you just need path: ‘/’ in the part that writes, or you end up with multiple cookies

    $.cookie(‘menustate’, hid, { path: ‘/’, expires: 2 });

    • mikecentola on July 3, 2009

      Thanks for the correction! 🙂

  • Per Jensen on August 13, 2009

    Many thanks for sharing.

    The variable ‘hid’ never did get a value in my setup (Ubuntu 9.04 Firefox 3.013, jQuery 1.3.2, ui 1.7.2). I have tried different things. this works for me:

    jQuery(document).ready(function(){
    var drawer = jQuery.cookie(‘accdrawer’);
    if(drawer === undefined) {
    drawer = “0”;
    }

    jQuery(‘#accordion’).accordion({
    header: ‘h3’,
    navigation: false,
    active: parseInt(drawer),
    autoHeight: false,
    clearStyle: true,
    collapsibe: true,
    alwaysOpen: true,
    animated: ‘slide’,
    change: function(event,ui) {
    var index = jQuery(this).find(“h3”).index(ui.newHeader[0]);
    if (index > -1) {
    jQuery.cookie(“accdrawer”, index, {path: “/”});
    }
    }
    }
    );
    });

  • Roman on August 18, 2009

    Example of this working would be really nice, since I just can’t make it work 🙁

    • mikecentola on August 20, 2009

      I know I know! It’s coming soon. I swear! 🙂

  • Taeke on August 27, 2009

    Thanks Per Jensen,

    I didn’t get the cookie thing to work but your solution works like a charm

  • Help Seeker on September 27, 2009

    Per Jensesn,
    Thanks for your suggstion. It seems to e working for un-nested accordions, but for nested I’m having trouble as is collapses all as soon as I click on the sub-accordion. Here’s my code:

    jQuery(document).ready(function(){
    var drawer = jQuery.cookie(‘accdrawer’);
    if(drawer == undefined) {
    drawer = “0”;
    }
    jQuery(‘#accordion2’).accordion({
    header: ‘h3’,
    navigation: false,
    active: parseInt(drawer),
    autoHeight: false,
    clearStyle: true,
    collapsible: true,
    alwaysOpen: true,
    animated: ‘slide’,
    change: function(event,ui) {
    var index = jQuery(this).find(“h3”).index(ui.newHeader[0]);
    if (index > -1) {
    jQuery.cookie(“accdrawer”, index, {path: “/”});
    }
    }
    });
    });

    Main

    Search
    Test
    Review

    Database

    Summary

    Dashboard

    Summary

  • Stuart on October 29, 2009

    Hi Mike,
    Thanks for the code.
    Any news on when you might have a working example?

  • kibi on November 6, 2009

    Thanks for article.
    How to store nested list accordions ?
    In you example http://www.truenegative.com you have 1 level accordion with
    Here it is nested list accordion – http://blog.evaria.com/wp-content/themes/blogvaria/jquery/index-multi.php
    Any ideas?

    Thank you for answer 🙂

  • Parker Hillius on November 18, 2009

    Setting the navigation attribute to true will let the accordion automatically handle this for you.

    From jQuery Documentation:

    navigation

    Type:Boolean
    Default:false

    If set, looks for the anchor that matches location.href and activates it. Great for href-based state-saving. Use navigationFilter to implement your own matcher.

    • mikecentola on November 18, 2009

      Right, that will work for having the anchor tag in the address bar. Using a cookie circumvents that. I can’t remember why I didn’t want it in the address bar, but it will come to me haha.

  • Cool Dude on January 11, 2010

    Your site was extremely interesting, especially since I was searching for thoughts on this subject last Thursday.

    I’m Out! 🙂

  • maumau on September 3, 2010

    thanks for sharing, just a little bug, pay attention, in the code is written “collapsibe” instead of “collapsible”.

  • Wim Symons on September 23, 2010

    Thanks, your article saved my day! And another big thanks to HelpSeeker, as it was his posted changes which made it all work.

  • mikecentola on October 4, 2010

    @maumau Thanks! Fixed the typo 🙂

  • Vojtech Zíka on October 17, 2010

    Hi,
    thanks for the cue.

    I´ve found one bug – when I implemented thi code to my site, it was working fine, but sometimes, the active field collapsed back to “inactive” state. So I was trying to fix it and there is the solution. If you are experiencing the same, set the parameter “Navigation” to false value.

  • George on November 27, 2010

    Very useful and thanks very much for sharing.

  • Justin on December 27, 2010

    Any idea on how to have this work per page? If I copy this page into a new page, jq and all, it reads the cookie. If a site uses multiple accordions this is not how it should work.

  • Anders on April 8, 2011

    How can I make this accordion move more smoothly?

    It’s ok when it’s opening but when closing a panel it’s not smooth at all.

  • Roland on August 3, 2011

    Nothing I found here worked for my particular installation. I developed my own way using the index, if anyone finds this useful:

    $(document).ready(function() {
    $(‘#accordion’).accordion({
    autoHeight: false,
    collapsible: true,
    active: false,
    change: function(event,ui) {
    var index = ui.options.active;
    if (index > -1) {
    $.cookie(‘accidx’, index, {expires: 2, path: ‘/’});
    }
    }
    });
    if ($.cookie(‘accidx’) > -1) {
    var idx = Number($.cookie(‘accidx’));
    $(‘#accordion’).accordion(‘option’, ‘animated’, false);
    $(‘#accordion’).accordion(‘activate’,idx);
    $(‘#accordion’).accordion(‘option’, ‘animated’, ‘slide’);
    }
    });

  • iceberg on September 21, 2011

    Here’s a working example (except for the cookie getter/setter)

    jQuery(document).ready(function() {

    var selected = readCookie(‘activeMkt’);
    var select = -1;
    if (selected){
    select = parseInt(selected);
    }

    $( “#accordion” ).accordion({
    header: ‘h3’,
    autoHeight: false,
    navigation: true,
    collapsible: true,
    alwaysOpen: false,
    animated: ‘slide’,
    active: select,
    change: function(event,ui) {
    var sel = ui.newHeader.children(‘a’).attr(‘id’);
    if (sel === undefined) {
    setCookie(‘activeMkt’,’-1′);
    } else {
    setCookie(‘activeMkt’,sel);
    }
    }
    });

    });

    EINS
    EIN

    ZWEI
    ZWE

    DREI
    DRE

  • konteyner on October 1, 2011

    thanks for your sharing,I use accordion menu on my website…

  • Gautham Sarang on October 2, 2011

    I am very much new to Jquery. what I want is something very simple. Could anyone please tell me how to achieve this.

    I have two menu’s which needs to be ‘remembered’ by the browser.
    1. A menu that is hidden initially and shown when clicked on a link
    2. I have put ‘help-hints’ allover the site. There is a button to hide the hint icons.

    What I want is : Once that main menu is shown, it should stay shown while browsing through the pages. Same with the hint icons. When someone clicks on the link that hides/shows the hint icons, they should get hidden/displayed.

    The following is my code :

    JQuery :

    jQuery(‘.slideout’).click(function() {
    jQuery(‘.sf-green’).slideToggle();
    jQuery(‘.slideout, .slidein’).toggleClass(‘slidein slideout’);
    });

    jQuery(‘#infobutton’).click(function(){
    jQuery(‘.info_on, .info_off’).toggleClass(‘info_off info_on’);
    jQuery(‘.hint, .hintoff’).toggleClass(‘hintoff hint’);
    });

    HTML

    Main Menu

    Help »

    Any help will be great!

    Thank you!

  • George on November 23, 2011

    Thank you so much! you saved my day on implementing this in my website haha love you~

  • Manny on November 25, 2011

    Useful and brilliant thank you for sharing this. save me today this did.

  • Daniel on August 3, 2012

    Just used it today with some edits.

    cookie plugin can be found here: https://github.com/carhartl/jquery-cookie

    I’ve put it on jsbin for easy cut’n’pasting
    It only works in edit mode though,
    http://jsbin.com/ekuhap/1/edit

    thanks!

  • Marc on August 21, 2012

    Thanks everyone for sharing, I combined a few of these ideas, which let me understand what was is going on.

  • Gianpiero on October 8, 2012

    Simplest solution:

    $(function () {
    var myact = false;
    $( “#myaccordion” ).accordion({
    clearStyle: true,
    collapsible: true, // allow to close completely
    create: function (event, ui) {
    //get index in cookie on accordion create event
    if (($.cookie(‘saved_index’) != null) && ($.cookie(‘saved_index’) != ‘false’)) {
    myact = parseInt($.cookie(‘saved_index’));
    }
    },
    change: function (event, ui) {
    //set cookie for current index on change event
    myact = ui.options.active;
    $.cookie(‘saved_index’, null, { expires: 2, path: ‘/’ }); // session cookie
    $.cookie(‘saved_index’, myact, { expires: 2, path: ‘/’ });
    },
    active: ($.cookie(‘saved_index’) == null) ? 0 : ($.cookie(‘saved_index’) == ‘false’) ? false : parseInt($.cookie(‘saved_index’))
    });
    });

  • mehdi on October 18, 2012

    thanks for your help.if i want do it by myself i have to spend two hour except 5 minutes.
    with the best wishes.

  • bhavesh on July 18, 2013

    for more informatoion about accordian menu visit this blog
    lessonsone.blogspot.in and get live demo with free download.

  • ello on July 21, 2013

    Hi, this is soo nice feature but I just dont get it to modify my jquery ui accordion 🙁
    Do I need the jquery.cookie.js plugin?
    this is my code:

    $(“.accordion”).accordion({
    canToggle: true,
    canOpenMultiple: true,
    change: function(event,ui) {
    var hid = ui.newHeader.children(‘a’).attr(‘id’);
    if (hid === undefined) {
    $.cookie(‘menustate’, null);
    } else {
    $.cookie(‘menustate’, hid, { path: ‘/’, expires: 2 });
    }
    }
    });
    // check cookie for accordion state
    if($.cookie(‘menustate’)) {
    $(‘#menu’).accordion(‘option’, ‘animated’, false);
    $(‘#menu’).accordion(‘activate’, $(‘#’ + $.cookie(‘menustate’)).parent(‘h3’));
    $(‘#menu’).accordion(‘option’, ‘animated’, ‘slide’);
    }

    THANKS in advance for your help.
    regards from germany

Leave a Reply