jQuery Tip: Scroll to the top of active accordion items whenever a new item is expanded (with the option to account for a fixed header)

Here is a really handy tip on how to add functionality for a user to be scrolled to the top of the currently active accordion item whenever a new accordion item is expanded. The key here, and the one that I have spent more hours than I care to remember trying to figure out, is to calculate in the the height of the already-open-but-now-closing accordion item.

Let’s assume your HTML markup looks something like this:

<div class="accordionWrapper">
<div class="accordionButton" id="id1">Accordion #1 Title</div>
<div class="accordionContent">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut accumsan erat eleifend ipsum hendrerit mattis. Pellentesque in urna non eros fringilla suscipit et quis velit. Pellentesque pulvinar hendrerit interdum. Morbi scelerisque est rutrum, porttitor odio sed, interdum velit. Sed lobortis, nulla vitae tincidunt varius, diam metus malesuada odio, at commodo nunc sem vitae justo. Sed eu eros a lorem feugiat blandit eu id arcu. Curabitur ultrices massa vitae tempor lacinia. Integer ac ligula elit. Aenean vel porta nisl. Aliquam ac justo erat.
</div>
</div>
<div class="accordionButton" id="id2">Accordion #2 Title</div>
<div class="accordionContent">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut accumsan erat eleifend ipsum hendrerit mattis. Pellentesque in urna non eros fringilla suscipit et quis velit. Pellentesque pulvinar hendrerit interdum. Morbi scelerisque est rutrum, porttitor odio sed, interdum velit. Sed lobortis, nulla vitae tincidunt varius, diam metus malesuada odio, at commodo nunc sem vitae justo. Sed eu eros a lorem feugiat blandit eu id arcu. Curabitur ultrices massa vitae tempor lacinia. Integer ac ligula elit. Aenean vel porta nisl. Aliquam ac justo erat.
</div>
</div>
</div>

Here is the jQuery you can take and recycle as you see fit:

$(document).ready(function() {
$('.accordionButton').click(function() {
  	var thisParent = $(this).parent();
  	var trigger = $(this);  
  	var openAccordionHeight = $(thisParent).prevAll('.active').children().eq(1).outerHeight();
       if ($(thisParent).hasClass('active')) {
	        $(this).next().slideUp('normal');
	        $(thisParent).removeClass('active');
	        return;
       } 
       $('.accordionContent').slideUp('slow');
       $('.active').removeClass('active');
       $(thisParent).addClass('active');
       $('html,body').animate({scrollTop: $(trigger).offset().top-openAccordionHeight}, 500);
       $(trigger).next().slideDown(500);
   });

});

And here is the code to use if you have a fixed header and need to calculate that in as well:

$(document).ready(function() {
$('.accordionButton').click(function() {
   	var headerHeight = $('.header').outerHeight();
  	var thisParent = $(this).parent();
  	var trigger = $(this);  
  	var openAccordionHeight = $(thisParent).prevAll('.active').children().eq(1).outerHeight();
       if ($(thisParent).hasClass('active')) {
	        $(this).next().slideUp('normal');
	        $(thisParent).removeClass('active');
	        return;
       } 
       $('.accordionContent').slideUp('slow');
       $('.active').removeClass('active');
       $(thisParent).addClass('active');
       $('html,body').animate({scrollTop: $(trigger).offset().top-openAccordionHeight-headerHeight}, 500);
       $(trigger).next().slideDown(500);
   });

});

Meet the author

Libby Fisher is an experienced freelance web developer, recently relocated from Seattle to Boston, and passionate about developing websites that are both aesthetically appealing and intuitively usable - or as she prefers: "beautifully effective."