A couple of years ago I published some tutorials on building an accordion style list in Ionic. The method covered in that tutorial works well enough, but in this tutorial I will be taking another look at building an accordion list, this time with a non-comprising approach to creating a high performance accordion component.

You can see this in action here or in the application preview component to the right (if you are on desktop).

The main issue with building an animated accordion component is that you would naturally animate the height of the content that is being opened in the accordion list. This is what gives it that “accordion” feel. One item expands pushing the other down, and then when it is closed it collapses all of the items below it back again. However, the problem with animating height is that it is bad for performance. Animating height will trigger browser “layouts” as items are pushed around the screen and need to have their positions recalculated. This is an expensive process for the browser, especially if it needs to do it a lot (e.g. as it does when animating the height of an item in an accordion list).

In some scenarios, animating height might still keep your application peformant enough to be acceptable, but if we want to animate whilst maintaining a high degree of performance we should focus on animating only the transform property for this kind of behaviour. That’s easier said than done, though. The good thing about a transform is that it only impacts the element being transformed, meaning that the positions of other elements on the screen won’t be impacted and so the browser doesn’t need to perform expensive layout recalculations. The bad thing for our scenario is that we want the other items in the list to be impacted - when one item is opened, all the other items need to move down the screen.

To solve this catch-22 situation, we use a trick that I also made use of in Advanced Animations & Interactions with Ionic to create a high performance delete animation.

The Trick

Before we get into the code for this I want to highlight how the concept works in general, otherwise things might get a bit confusing. Here’s the general process for how opening an accordion item will work:

  1. An accordion item is clicked
  2. The content for the item is displayed immediately (no animation)
  3. Every item below the item being opened is transformed up so that it hides the content that was just displayed (at this point, there will be no noticeable change on screen, because the items were just transformed back into the position that they were at initially)
  4. The elements that were just transformed up have the transforms animated away. This will cause them to slide down to reveal the content that was just displayed.

By translating the position of all of the items below the one being opened, we can give the appearance of the height of the content being animated, but really everything else below it is just being moved out of the way with a transform. The one remaining issue with this is that since we rely on the elements below the one being opened to initially block the content from being visible, we run into a problem when either:

  1. The last element in the accordion list is being opened (it won’t have anything to block the content, so the content will jsut appear immediately and won’t be animated)
  2. The content for an item earlier in the accordion list is long enough that it extends past the bottom of the list anyway, in which case we will see the content leaking out of the bottom of the list.

To handle this, we create an invisible “blocker” element that sits at the bottom of the list, and will change its height dynamically to make sure it is large enough to block any content from being visible (e.g. if the item being opened has content that is 250px high, the blocker will dynamically be set to a height of 250px). If you’re thinking - hey! you said we weren’t going to use height - the important difference here is that we are not animating the height, it will just instantly be set to whatever value we need.

To make this blocker “invisible” we have to set it to be the same colour as the background, which creates one weird limitation for this component that it can only be used on pages with a solid background colour (e.g. not a gradient or image).

Even with this overview description, I still think the concept is a bit confusing. To help, I’ve created a diagram of what this process actually looks like. I have given the “blocker” element an obvious colour, and reduced the opacity of the items so that we can better see what is going on behind the scenes:

Diagram of how the accordion list open animation worksIn this example, the blocker isn’t actually necessary because we are opening the second item in the accordion list and the content is not long enough to extend past the bottom of the list. However, if this item was one of the last two items the blocker would come into play to hide the content.

Once you understand this process, closing the item again is quite a bit simpler. We just first animate all of those items back with a transform so that they are covering the content again, and once they are covering the content we remove the content (basically the same process, just in reverse).

#ionic

High Performance Animated Accordion List in Ionic
2.85 GEEK