Animated Accordion With Vue JS Transitions

Ready for this essential page element implemented
with Vue JS? Today I’ll show how you can build your own
accordion. Let’s start right now. What’s going on, my name is Mario, welcome
to another video. If this is your first time here and you wanna
learn more about Vue JS or other related stuff, start now by subscribing and clicking the
bell so you don’t miss anything. Ok, we have this nice accordion here, with
this smooth opening and closing animation. On top, we have here an arrow, which rotates
if you click an item in the list. Now, if you need to animate an HTML element
from zero height to its natural height, then that can be quite problematic. The element just appears directly, instead
of an animation. There are some solutions to fix this age-old
problem, like if you use the min-height attribute or the scaling with transform, but all of
these methods have their disadvantages. So using JavaScript for triggering and controlling
transitions is almost essential. And Vue.js provides us a beautiful transition
component which makes animating HTML elements a very pleasant experience. So there are hardly any reasons not to use
JavaScript to animate elements if you are using Vue JS. I have already prepared some files,
so let’s take a look. The starting point is again the App.vue file
and I have already created two more components. The List and the ListItem Component. Our root component here renders only the List
Component and we have here some global CSS definitions. I have included here the font awesome library and a different font, just for the look and feel. I close this file, we don’t need to adjust
anything here. Straight to the List Component. So the template renders nothing, only the
ListItem component is imported here and I have prepared some test data for the list. I keep it simple with a title, a status if
the list is open up or not and for each element an array, and this can be just links or something
else. You can use this as a sidebar navigation or
faq list, for example. There are a lot of use-cases. Last but not least, the ListItem Component,
only with the basic structure. Ok. let’s stick to the List Component, respectively
to the template. And I wanna output here our list so I create
an unordered list element with the class wrapper. Further a list element, one list element,
with a v-for loop, and I gonna fetch here the item and the index from our list. And as a key, I use the name item and the
current index. The first thing is I wanna output here the
title from each list element, so I create a new div with the class title, and between
this tags here I gonna use the awesome, amazing, fancy string interpolation syntax with this
double curly braces here and output the title, in the end. Time for the first save and let’s see what’s
going on. Hmm, ok. Let’s style this list a little bit. And define here the wrapper class. We don’t need the list styling, I set this
to none. That could be quiet the default behavior. I change this to ‘none’ twice a day, in the
past 20 years of my developer experience. That’s about 14000 times. Too much. Ok next, we need some color, I set the background
color to ‘fefefe’, a little bit white, not too much. And a box-shadow would be nice, only below,
so I write 0 and only 2 pixels, it’s a tiny shadow, as a color I wanna use black with
a lot of transparency here. Hmm, border-radius would also be nice, I set
it to 4 pixels. For the final touch. And overflow hidden is always a good idea
if you are using border-radius. Ok, straight to the list item. I set this element to position relative, I
wanna use some absolute elements later. Next to the color, I gonna use a dark grey
color, like this. And I need a border, to the top, one pixel
is enough, solid and with the color ‘dedede’. ‘dedede’ is just the same as ‘fefefe’,
but not quite so white. And last but not least, let’s change the
cursor to ‘pointer’ for this element. So we also have a title, a little spacing
would be nice so I set here padding to the top and bottom and zero to the left and right
side. I wanna space the text inside with text-indent,
maybe 20 pixels. With this, I save and let’s take a look. Ok looks fine. Next, I wanna create a hover effect. And I change the color. And the background color as well, to a light
green. Ok, I save and let’s see if that fits. Hmm, looks pretty awesome. Next and the last thing in this Component,
I wanna have an icon on the right side, which rotates if I click the list item. So, let’s use here an icon from the font
awesome library. The chevron circle right icon. And I gonna bind a different class to this
icon, open, if the status equal to true. And we need a click event right here on the
title, and I wanna change the open status to the opposite if I click. So with this, we can create the CSS definitions. I set the icon position to absolute this should
be displayed on the right side with a little spacing to the top and right. And if the open status connected to the icon,
respectively if the open status equal to true, then I wanna rotate this icon 90 deg to the
bottom. Ok, I think we can take a look. Nice, I like it. I think we are done here in this component,
straight to the next, the ListItem Component. First I pick up the provided data with props,
we get here the list. By the way, I have forgot to output the ListItem,
so let’s do this quickly, and I provide here the item as list. Ok back to the template, I wanna output an
unordered list again, with the class list-item and one list element with the class sub-items,
for the styling in a few seconds. And here I wanna output each item with a loop,
v-for, and I need the item and the current index, in list and I wanna output the sublist
here. As key, I choose simply the index. And last but not least I output here the item,
it’s a string in this case. Let’s style our amazing new list here,
first the list-item class. And set the list-style to none, again, you
know. Next, I wanna style the sub-items, padding
with 10 pixels for a little bit spacing. It’s a sublist, so I use text-indent with
20 pixels. Next, I define some colors. And a border to the top. A hover effect would be nice, where I change
the colors. Quicksave, and now, yeah looks really nice
now, all the list items are displayed, but no worries, we make the fancy stuff now. Let’s implement the transition for the opening
and closing animation. So let’s stick to the template, and we need
here the transition component, provided by Vue JS. I explained it a little bit in my last tutorial,
with the animated grid layout. I link it in the video description. But if you want a complete basic tutorial
about it, leave a comment, I would like to know if you need a further tutorial. So, we have here the transition component
and now I set here for the CSS Animation a name, maybe expand. And I’ll put a condition with v-show here
in the list if the open status is true, then the list will be displayed, otherwise not. Ok, let’s go to the style section and create,
the enter class, I set the height to zero. And the enter-active class for the opening
animation. I use the transition property, applied to
the height, with this duration and I choose simply the ease-in-out animation. And I set overflow to hidden. Now, do you think this works? Hmm, I save and let’s see what’s going
on. And you see, the list just appears directly. The animation is not working. That’s the problem I was talking about at
the beginning. Now how can we fix this, there are some workarounds,
but all of these methods have their disadvantages. I want to go another way. I wanna control the animation with a little
bit Javascript. And for that, Vue JS provides a lot of event
hooks you can use. The first is the enter hook. And between the quotation marks, you can call
a function, I write here enter and I create it later in a few seconds. The next one is the after-enter hook. And we need in this case also the leave hook,
for the closing animation. So, let’s create these three methods, enter,
afterEnter and leave. And each function gets automatically the element. Ok, let’s begin with the enter method and
first I set the element height to auto. Next, I gonna hold the height value, and there
is a nice javascript function, getComputedStyle and this returns an object containing all
the CSS properties of the element after all active styles have been loaded and the basic
calculations have been performed. And this is the important thing here. We need the height after all basic calculations
have been performed, then the height of each element here is dynamically, based on the
number of items in the sublist. So with this function, we get the height from
the element you pass here and we don’t need the complete object, only the height, so I
can write here simply height. And now I set the height to zero. The last step is to set the height from the
element to the calculated height. But this only will not work, you need here
a little trick, because we need to make sure the browser has finished the painting after
setting the height to zero. And you can do this simply with the ‘setTimeout’
function. If you want to force the repaint to make sure
the animation is triggered correctly, then you can fire the method getComputedStyle again. This is not necessary, but sometimes the animation
may not start depending on the case. But essential is here the order, keep in mind,
set first the height to his natural height, then pick up the calculated height with ‘getComputedStyle’,
next set for the opening animation the height to zero, then you can make sure the animation
is triggered correctly and as the last step, you should set the height from the element
to the calculated height. With ‘setTimeout’ you make sure, that
the browser finished the output before you change the height again. Ok, that’s it. In the afterEnter function, we only need to
set the height to auto. And the leave function is almost the same
as the enter function. Only the other way around. First, you have to pick up the calculated
height, so I copy this line here quickly and set it to the element. Then you can make sure the animation is triggered
correctly. And as the last step, we set the height back
to zero. Yes I know, it looks a little bit strange,
but the important thing is it works, I hope. By the way, you can delete these CSS classes
here, you only need the enter-active definition for the transition, in this case. And I see, I have forgot the CSS class for
the closing animation, so let’s add this here quickly. So I save now and let’s check what’s going
on here. Ok, the opening animation works fine, but
the closing animation, hmm, I think there is a bug in the leave function. This is wrong here, the classic copy-paste
failure, I don’t wanna hold the height here, instead I wanna set the height to the element. I save again. And yes, it works pretty well. Amazing. With this, I would like to promote my Patreon
page to support my YouTube channel. And your support pushes me and gives me the
ambition to keep going and keep bringing you the best content possible and making you a
better web developer. If you like my tutorials and you wanna support
me, then you have some benefits, you get the source code from my tutorials, and this includes
comments and tips, you get a special rank on my Discord server, you can vote for new
tutorial topics and much more. Apart from that, you can always come to my
discord, where we can discuss and help each other. You find the links below in the video description. Thank you so much for watching. I’ll see you next time.

Be the first to comment

Leave a Reply

Your email address will not be published.