Igor Kromin |   Consultant. Coder. Blogger. Tinkerer. Gamer.

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.


A quick disclaimer...

Although I put in a great effort into researching all the topics I cover, mistakes can happen. Use of any information from my blog posts should be at own risk and I do not hold any liability towards any information misuse or damages caused by following any of my posts.

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.
Hi! You can search my blog here ⤵
NOTE: (2022) This Blog is no longer maintained and I will not be answering any emails or comments.

I am now focusing on Atari Gamer.