Slide up/down animation with AlpineJS

With CSS it is not possible to transition the height property to auto:

1.collapsible {
2 height: 0;
3 overflow: hidden;
4 transition: height .3s;
5}
6 
7.collapsible.is-open {
8 height: auto;
9}

For years developers relied on jQuery's (or Velocity's) slideUp() and slideDown() methods to perform slide up/down animations without setting a fixed height. In fact, I remember being brought into projects where jQuery was added to the project just for these 2 methods.

Here is how to implement slide up/down animation with Alpine JS.

Component set up

Start with an Alpine component with a property to manage the open state of a collapsible element. And let's add a .collapsible element.

1<div x-data="{isOpen: false}">
2 <div class="collapsible">
3 <!-- your content -->
4 </div>
5</div>

CSS

Then we add the CSS styles for the collapsed state:

1.collapsible {
2 height: 0;
3 opacity: 0;
4 overflow: hidden;
5 transition: all .4s;
6 pointer-events: none;
7}

And then we add the CSS for the expanded state (excluding the height which we'll manage with Alpine):

1.collapsible.is-open {
2 opacity: 1;
3 pointer-events: auto;
4}

The magic

What we want to do when the isOpen property is set to true:

  1. Add the .is-open class to the .collapsible element
  2. Programmatically set a height to the .collapsible element

For (1), we'll use x-bind to conditionally set a class based on the value of the isOpen property. This can be written as x-bind:class or :class:

1<div x-data="{isOpen: false}">
2 <div
3 class="collapsible"
4 :class="isOpen && 'is-open'"
5 >
6 <!-- your content -->
7 </div>
8</div>

For (2), we'll also use x-bind, but to add some inline styles. We'll add the height property and give it a value we calculate with JS.

"Calculate" is a misleading term here. We are going to literally read the height of the element using scrollHeight which includes the height of an element's visible and invisible content. We'll access the element's DOM node using Alpine's $el magic property.

1<div x-data="{isOpen: false}">
2 <div
3 class="collapsible"
4 :class="isOpen && 'is-open'"
5 :style="isOpen && {height: $el.scrollHeight+`px`}"
6 >
7 <!-- your content -->
8 </div>
9</div>

Here is the full demo including a button to expand/collapse the element:

See the Pen AlpineJS: slide up/down animation by Hussein Al Hammad (@hus_hmd) on CodePen.