@ryantdecker has the most common answer available. I prefer doing less code though and do class binding instead:
<template>
<!-- isShowing either data or computed... -->
<div class="foo" :class="{ showing: isShowing, hidden: !isShowing }">
<p>
something here where the height is not constant
</p>
</div>
</template>
...
<style>
.foo {
height: auto;
transition: max-height 0.5s;
&.showing {
max-height: 200px; /* MUST BE GREATER THAN height:auto */
}
&.hidden {
max-height: 0px;
}
}
</style>
A few customizations that can be done for even more control are:
- Set
:style="{'max-height': computedHeight}"
- Use
ease-in and ease-out with two different transitions within the .showing and .hidden classes respectively.
- Use a cubic bezier transition speed for really long contents that collapse/expand
The first customization above can be used when you are using distinct items, like pictures, flex rows where the height can be seen via devtools and the height calculated. E.g.:
computed: {
/**
* @return {string} max height of the container in pixels if shown else zero
*/
calcedHeight()
{
const elHeight = 80;
const maxHeight = this.isShowing ? elHeight * this.elementCount : 0
const maxHeightPx = maxHeight + 'px'
return {
'max-height': maxHeightPx
}
}
}
This could easily be made into a component with isShowing, elHeight, and elCount props at this point.
Cubic Bezier
I am giving this it's own section because it might be all that is needed in regards to crazy long elements (think 5000px max-heights):
&.showing {
transition: all 0.6s cubic-bezier(1, 0.01, 1, 0.01);
}
&.hidden {
transition: all 0.6s cubic-bezier(0.01, 1, 0.01, 1);
}