Igor Kromin |   Consultant. Coder. Blogger. Tinkerer. Gamer.
Notice: I'm taking a break from blogging to focus on Atari Gamer . com, check it out!

NOTE: This article is 3 years or older so its information may no longer be relevant. Read on at your own discretion! Comments for this article have automatically been locked, refer to the FAQ for more details.
I've recently discovered a problem in a website I've built where clicking a Bootstrap 3 accordion panel to expand it and show the content would erroneously scroll that panel off screen. This was happening because the content was being loaded dynamically via the show.bs.collapse event. After a bit of playing around with the implementation I found a way to scroll the panel, including its heading correctly to the top of the screen.

It turns out that I was using an incorrect event, I should have been using 'shown' instead of 'show', since the former is fired after the Bootstrap's CSS animation completes, the latter is fired as soon as the panel is opened i.e. during the collapse animation. I also needed to scroll to the panel heading.

These screenshots demonstrate the problem. I have a number of collapsed panels, when a panel is shown, I dynamically load its content, which can have a variable height, depending on the panel.

If the panel was close to the top of the screen, once the dynamic content loaded, it would be shown incorrectly off-screen.

Whereas, this is what should have been happening...the panel and its heading being shown at the top of the screen instead.

This is how I solved it...the divId calculation is not shown here as that can be implementation specific, I also don't show the URL of the dynamic content I'm loading since that is not relevant to this example.
$('#accordion').on('shown.bs.collapse', function(e){
divId = xxxx; // <-- works out the ID of the DIV to load into
$('#' + divId).load(xxxx); // <-- loads dynamic content once the panel is shown
// finds the panel heading element
scrlTo = $('#' + divId).closest('.panel').find('.panel-heading');
// scrolls the panel heading to the top of the window with a 6 pixel gap at the top
$('html,body').animate({ scrollTop: scrlTo.offset().top - 6 }, 50, 'swing');

For the above to work, I nest a div element with and ID inside my panel-body div, like this...I've simplified this slightly, my actual div has a loading animation and the ID is assigned dynamically using PHP.
<div class="panel-body">
<div id="id1">Loading...</div>

So now whenever I click a panel heading to expand it, it's scrolled to the top as expected. There is a small delay while loading the dynamic content, but positioning happens before this content is loaded. The video below demonstrates this in action.


Skip down to comments...
A quick disclaimer...

Although I put in a great effort into researching all the topics I cover, mistakes can happen. If you spot something out of place, please do let me know.

All content and opinions expressed on this Blog are my own and do not represent the opinions of my employer (Oracle). Use of any information contained in this blog post/article is subject to this disclaimer.
comments powered by Disqus
Other posts you may like...