Make an animated expanding list/accordion in Vue
I had to do a bit of research to put together all the parts for this feature, so it’s worth writing down for future reference I think! Here is a demo:
Yeah, I used Taco Bell locations again because it’s handy JSON data that I have lying around.
There are two sides to building this feature: the animation, and controlling the child components visibility state.
A summary of what I learned
(‘TIL’ for the kids)
- You can’t animate CSS height. Animate
max-height
instead and use an arbitrarily large figure for the expanded height - You have to use the Vue
<transition>
element and match up the transitionname
with some CSS classes which implement the animation - A Vue component shouldn’t alter parent state but can pass changes up to the parent by emitting a custom event, captured by a handler (at parent level) on the child element. See code samples below:
In the parent:
<!-- Pass in the show/hide status, the site data, and attach event handler for when the child wants to collapse itself -->
<site-details :show="site.show" :site="site" @collapse="toggleShow(site)"></site-details>
In the child component:
<!-- The close button -->
<span class="fr pointer f1" @click="$emit('collapse')">×</span>
For more technical info, I wrote documentation in the README on Glitch
Also
One more gotcha I discovered in this process: Initially the source JSON data didn’t have a show
property, so I had a snippet in Vue’s mounted
event something like this.locations.forEach(s => s['show'] = false)
to set the data up. But, when this was in place, nothing would show or hide. I don’t know if it was because I used array indexers or because modifying the state object like that makes a mutable copy. Either way, it didn’t work. So I had to modify the original JSON and add a show
property to every item by hand (that is, with a Notepad++ macro).