Skull Jackpot

Various thoughts of minimal interest to others

Quick and dirty (but useful) jQuery accordion pattern

March 30, 2009

It’s fairly common to want to have multiple panels on a page, only one of which should be visible at any given moment. There are too many jQuery accordion examples to count. I recently knocked together a handy general case, which includes a novel piece of functionality. What makes this one different? You can specify an arbitrary panel to be expanded upon page load, without any server-side code.

The HTML

<div class="expand">
<h2 id="expand-an-element" class="toggler">This will be clickable, once the javascript runs</h2>
<div class="togglee">
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sapien. Phasellus nunc. Vestibulum consectetur tortor eu urna. Donec quam. Vivamus id neque a nisl iaculis vulputate.</p>
  <p>Multiple elements can be contained within the <code>togglee</code> parent.</p>
</div><!-- /.togglee -->
<h2 id="expand-this-element" class="toggler">Another toggler element</h2>
<div class="togglee">
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sapien. Phasellus nunc. Vestibulum consectetur tortor eu urna. Donec quam. Vivamus id neque a nisl iaculis vulputate.</p>
</div><!-- /.togglee -->
</div><!-- /.expand -->

Note: the expand, toggler, and togglee elements aren’t limited to the example above – they can be any valid HTML element. The only assumptions are that the expand will be a parent, and that each toggler immediately precedes the associated togglee element.

The CSS

.expandable .toggler {
cursor: pointer;
}

.expandable .togglee {
display: none;
}

You can also apply styles to the toggler element by targeting the expanded class. This will only be added to togglers which are currently expanded, which allows you to provide visual cues about the fact that it’s an active interface element.

The javascript

$(document).ready(function(){
  $('.expand').addClass('expandable');
  $('.expandable .toggler').click(function() {
    var target =  $(this).next('.togglee');
    if (target.is(':hidden')) {
      var togglees = $('.togglee');
      for (i=0;i<togglees.length;i++){
        $(togglees[i]).slideUp().prev('.toggler').removeClass('expanded');
      }
      $(target).slideDown().prev('.toggler').addClass('expanded');
    }
  });
  var initialExpansion = "";
  if(document.location.hash) initialExpansion = $(unescape(document.location.hash));
  if(!(initialExpansion.length)) initialExpansion = $('.expandable .toggler:first');
  initialExpansion.addClass('expanded').next('.togglee').css("display","block");
});

We use document.location.hash to access the portion of the URL beginning at the hash sign (#). Then, if there are any elements with a corresponding id, we apply our expand logic there (falling through to showing the first panel if there isn’t a match).

This allows us to construct links like http://example.com/path/to/page#expand-this-element, and have that panel begin in an expanded state.

Use and enjoy. If you have feedback or improvements you’d like to see, note ‘em in the comments.

Leave a comment

HTML - You can use:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>