A common UX problem to solve: When using accordions that contain a lot of content; if the user has already scrolled past an accordion item, if they click to open the next item, the content can appear to shoot up the page as the previous item closes (due to the page changing height). This means the user may need to scroll back up to find the start of the content to continue reading.
An age-old problem
The first thing to note is this isn’t an issue with Bricks, or a failure with accordion elements. If you ‘Google’ the term “accordion scroll” you’ll find pages of people asking this same question, coming across this same UX problem across different platforms, Webflow, Bootstrap, pretty much every WP theme that includes an accordion.
In this tutorial, we’ll look at two ways to solve it.
Is an Accordion the best solution for the content?
First, it’s important to zoom out and consider what is happening. The intended behavior of an accordion is to shrink the content down to zero height as each item is closed. It’s mainly designed for use with lists, such as short FAQs, where you want the user to be able to easily scan through the list of questions rather than having to scroll past more content to find the one they’re looking for. It’s not really designed for hiding entire sections of content.
As a result of the accordion items shrinking to zero height, the overall height of the page can change, sometimes by a lot. The browser is keeping track of the scroll position. If the page height is reduced by a lot, in order to preserve the scroll position, the content must move upwards. The browser isn’t going to automatically scroll the user to a different scroll position on the page.
It isn’t really a bug. Often it’s the result of a bad design decision, especially in the case of having lots of content, for example using entire sections inside accordions or any content where it’s larger than the viewport height.
Sometimes an accordion is just the wrong tool for the job. Most accordion elements will have the option to prevent other items from closing as one is opened, for exactly this reason. In Bricks it’s the ‘Independent toggle’ setting.
The real problem to solve
The real problem that is trying to be solved is..
‘I have a lot of content, not all of it needs to be seen upfront. I want to hide some of it while making it easy for the user to find the content when they need it’.
For this problem there are a few solutions; for example using tabs (where the links to open the content will always remain static at the top) or opening up the content inside of a modal/lightbox can all solve this without forcing any unnecessary scrolling that comes with changing page heights.
For smaller content, obviously using accordions can be an ideal solution. It’s only with larger content that there is an issue.
With that first solution out of the way, if it is absolutely necessary to use accordions with a large amount of content, and the previous items need to close, then we can always force the browser to scroll the user to the new position after the accordion has fully opened using JS..
Scrolling the User to the Open Accordion Item
Here’s how we can do this with JS, added to Bricks’ page settings > custom code > footer scripts (making sure to place inside script tags)
This is the solution for when using Bricks’ nestable accordion element. This will work when using query loops for the accordion items also (as no IDs are needed).
document.addEventListener("DOMContentLoaded", () => {
const accordionHeader = '.accordion-title-wrapper';
const delay = 200;
const offset = 200;
document.querySelectorAll(accordionHeader).forEach((header) => {
header.addEventListener('click', () => {
setTimeout(() => {
window.scrollTo({
top: header.getBoundingClientRect().top + window.pageYOffset - offset,
behavior: 'smooth'
});
}, delay);
})
})
})
The delay and offset variables can be changed to match the experience you want. A delay is often needed as it takes a few ms for the accordion item to finish closing. Until that moment, the new scroll position will be unknown. You may need to adjust the 200 to suit your situation better (depending on how long it takes for the accordion to close in ms).
Side note – if using BricksExtras’ Pro Accordion, which is a more accessible version of the Bricks nestable accordion, simply change the value of the ‘accordionHeader’ variable. The selector for that accordion header would be ‘.x-accordion_header’.
That’s it
Now each time an accordion header is clicked to open, the browser will smooth scroll the user to the new scroll position where that accordion header is (plus any offset that was added) after the accordion item has opened.
7 comments
wilhelm
Thank you so much!
Dirk Borchers
For me, this works fine with the normal accordion, but not with the ProTabs element, which only becomes an accordion on smaller devices. It doesn't add a class .accordion-title-wrapper to the open tab, it only changes the 'aria-expanded' to true. What's the solution here? Thanks
David Browne
You can use a similar method, the element has a class '.x-tabs_toggle' and there's an event that triggers "x_tabs_accordion:expand" whenever it expands that accordion item. The rest would be the same.
https://gist.github.com/wplit/9a092acbd6598d6d61e189d1f3b3ca97
Dirk Borchers
Cool, this works. Thanks, David
Joshua Knight
This just saved my bacon in 2 minutes! Thankyou ๐
Michael van Dinther
Fantastic! Thank you
Philipp Stakenborg
Thank you this works! ๐
It. took me some time, to figure out what variable to change with the bricksextras accordion. I did this wich was obviously wrong:
document.querySelectorAll(.x-accordion_header).forEach((header) => {