Bootstrap accordion, scroll to top of active (open) accordion on click?
Update 2021
As of Bootstrap 5, jQuery is no longer required. Here is a vanilla JavaScript solution of scrolling to the top of the open accordion item...
const accordionItems = document.querySelectorAll('.accordion-collapse')
const acc = document.getElementById('accordionExample')
accordionItems.forEach((el)=>{
el.addEventListener('shown.bs.collapse',(e)=>{
var scrollOffset = acc.scrollTop + el.parentNode.offsetTop
acc.scroll({
top: scrollOffset,
left: 0,
behavior: 'smooth'
})
})
})
Demo
You can animate the scroll by getting the top of the 'target element' and then calling animate on the body..
$('html, body').animate({
scrollTop: $("#target-element").offset().top
}, 1000);
modifying it to be something like this will help you achieve what you are after
$('.panel-collapse').on('shown.bs.collapse', function (e) {
var $panel = $(this).closest('.panel');
$('html,body').animate({
scrollTop: $panel.offset().top
}, 500);
});
source: http://www.abeautifulsite.net/smoothly-scroll-to-an-element-without-a-jquery-plugin-2/
complementary fiddle: https://jsfiddle.net/hjugdwbp/
Edit: 2018-05-25
Bootstrap 4 Example
Using the accordion example at: https://getbootstrap.com/docs/4.0/components/collapse/#accordion-example I have modified the code to support cards.
$('.collapse').on('shown.bs.collapse', function(e) {
var $card = $(this).closest('.card');
$('html,body').animate({
scrollTop: $card.offset().top
}, 500);
});
Fiddle: https://jsfiddle.net/agpkc4v2/1/
Edit: 2019-07-18
I made it 'prettier'...
Bootstrap 3
https://jsfiddle.net/erutfgvn/
$('.panel-collapse').on('show.bs.collapse', function(e) {
var $panel = $(this).closest('.panel');
var $open = $(this).closest('.panel-group').find('.panel-collapse.in');
var additionalOffset = 0;
if($panel.prevAll().filter($open.closest('.panel')).length !== 0)
{
additionalOffset = $open.height();
}
$('html,body').animate({
scrollTop: $panel.offset().top - additionalOffset
}, 500);
});
Bootstrap 4
https://jsfiddle.net/9p7f0hut/
$('.collapse').on('show.bs.collapse', function(e) {
var $card = $(this).closest('.card');
var $open = $($(this).data('parent')).find('.collapse.show');
var additionalOffset = 0;
if($card.prevAll().filter($open.closest('.card')).length !== 0)
{
additionalOffset = $open.height();
}
$('html,body').animate({
scrollTop: $card.offset().top - additionalOffset
}, 500);
});
Edit: 2021-04-20
Bootstrap 5
https://jsfiddle.net/hLzg0n2y/2/
$('.collapse').on('shown.bs.collapse', function(e) {
var $card = $(this).closest('.accordion-item');
var $open = $($(this).data('parent')).find('.collapse.show');
var additionalOffset = 0;
if($card.prevAll().filter($open.closest('.accordion-item')).length !== 0)
{
additionalOffset = $open.height();
}
$('html,body').animate({
scrollTop: $card.offset().top - additionalOffset
}, 500);
});
I am working on a project that needed the same functionality. Came up with the following code. I added the variables for clarification:
$('#accordion').on('shown.bs.collapse', function (e) {
var panelHeadingHeight = $('.panel-heading').height();
var animationSpeed = 500; // animation speed in milliseconds
var currentScrollbarPosition = $(document).scrollTop();
var topOfPanelContent = $(e.target).offset().top;
if ( currentScrollbarPosition > topOfPanelContent - panelHeadingHeight) {
$("html, body").animate({ scrollTop: topOfPanelContent - panelHeadingHeight }, animationSpeed);
}});