How to animate an auto-height element
Tags: css, javascript, html
Published: 2017-10-31 14:10:53

---
title: How to animate an auto-height element
published: true
description: CSS will not allow a transition to/from auto height.  This is a workaround.
tags: css, javascript, html
canonical_url: https://volumeintegration.com/animate-auto-height-element/
cover_image: https://volumeintegration.com/wp-content/uploads/christian-kaindl-332935-1030x687.jpg
---

Originally posted at [https://volumeintegration.com/animate-auto-height-element](https://volumeintegration.com/animate-auto-height-element/)

Animating an auto-height element seems like it should be fairly straightforward, however it seems <a href="https://www.google.com/search?q=animation+auto+height+element" target="_blank" rel="noopener">I'm not the only one who has struggled with this particular issue</a>.Â  The problem is usually some variant of the following:
<ul>
 	<li>I have some element I would like to allow to vertically expand and collapse.</li>
 	<li>The element has dynamic content - so therefore the height of the expanded element is unknown/dynamic.</li>
 	<li>I need to set the height of the element toÂ <code>auto</code> to allow the element to change height based on its contents.</li>
 	<li>CSS doesn't allow transitioning to <code>auto</code> height so - it just jumps to the height when expanding/collapsing.Â  No animation â˜¹ï¸</li>
</ul>
&nbsp;

This is what I want to do.

![Showing auto-height expander](https://volumeintegration.com/wp-content/uploads/expandy.gif)


<h2>Some Workarounds</h2>
You may find several potential solutions to this problem if you spend a bit of time poking around the internet.

For example - there is the <strong>max-height</strong> workaround.Â  In this solution you would basically transition the <code>max-height</code> attribute instead of the <code>height</code>.Â The trick is to set the final max-height to something way larger than you think the element will ever grow.Â  This will effectively animate to the height of the element's contents.Â  This might feel a little hanky to you - and for good reason. For starters - you have to guess what might be the largest the contents of the will ever get. But the content is dynamic - so that could easily get out of hand. Furthermore, the transition will animate to the full <code>max-height</code> specified. The visible height will stop at the height of the content - but the transition thinks it needs to grow all the way to the <code>max-height</code>. So for example - if you set a transition time of <code>300ms</code> - it will take that long to animate to the full <code>max-height</code> even though the visual height stops well before then.

Other workarounds involve hiding the visual elements instead of changing the actual height or using javascript to manually animate/hide elements etc., but these are even more complicated than the <code>max-height</code> solution and introduce a slew of new problems to deal with (the very least of which is wreaking havoc on the element's accessibility).
<h2></h2>
<h2>My <span style="text-decoration: line-through;">Hack</span> Solution</h2>
If you're the kind of person that peeks at the end of the bookÂ <em>(shame on you)</em> then you can check out <a href="https://codepen.io/marshallformula/pen/qPvWBL" target="_blank" rel="noopener">my working solution on codepen</a>.

It still uses CSS to animate the <code>height</code> property through the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transition" target="_blank" rel="noopener">transition property</a>.Â  However it also uses a bit of JavaScript to store some state for the element.

This solution will not work for all situations - but it suited my needs well, but there are some restrictions:
<ul>
 	<li>You must know the initial default height of the element.Â  This means if you don't know what content will be in your div on initial load - this might not work so well.Â  But if your element has an initial set of known contents this should work like a champ.</li>
 	<li>Content can only be added or removed from the element while it is in the expanded state.Â  If content is added/removed from the div while collapsedÂ  - then you're out of luck again.</li>
</ul>
Assuming your needs fulfill these requirements - this should work nicely.

The solution essentially works like this:
<ol>
 	<li>Store the initial height of the element in a variable somewhere. We'll call it <code>expandHeight</code> for now.</li>
 	<li>When the element expands - you can easily transition the height from 0 to the <code>expandHeight</code>.</li>
 	<li>After the transition is complete (use a <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout" target="_blank" rel="noopener">setTimeout</a> based on whatever you set the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transition-duration" target="_blank" rel="noopener">transition-duration</a>Â property to) then set the element's height property to <code>auto</code></li>
 	<li>Add/remove content to the element as desired</li>
 	<li>When collapsing -
<ol>
 	<li>First store the element's current height back into the <code>expandHeight</code> variable.</li>
 	<li>Next set the element's height back to a fixed value (what you just stored in expandHeight). This is because the element cannot transition <em>from</em> an <code>auto</code> height either. It can only transition to/from a fixed height.</li>
 	<li>Now you can transition back to a height of 0.</li>
</ol>
</li>
 	<li>When you need to expand again - just start at step 2 above and repeat as necessary!</li>
</ol>

That's about all there is to it and it has worked well for me. One caveat is that you may need to stick step 5.3 in another <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout</a> with a very small delay to allow the DOM time to register that the height attribute has changed from an auto height to a fixed height.

[Here's my fully functioning example on codepen.](https://codepen.io/marshallformula/pen/qPvWBL)

The astute observer might notice that it would not take too much imagination to create a <a href="https://reactjs.org/docs/higher-order-components.html" target="_blank" rel="noopener">high order ReactJS component</a> out of this solution that stores its own state internally so you can re-use it anywhere with ease.

Let me know what you think.Â  More importantly - let me know if you've got something even better!Â  Cheers!
<h6><em>Feature Photo by <a href="https://unsplash.com/@christiankaindl">Christian Kaindl</a></em></h6>