Throughout my career, in the projects I've worked on, giving animation to the unmounting of a component is not something that is given much importance. Even some component libraries don't do it.
Some people think that exit animations are too much and that components should simply disappear. Maybe it's because implementing an exit animation is not as simple as giving it an entrance animation.
In my opinion, a component with an enter animation should have an exit animation. Otherwise, it feels broken.
In this article, I will be explaining how to do it in a Modal component, but it can be used for whatever is needed, for example, components like Popovers, Tooltips, etc. First, I will go with a simple example, and then with a more complex, comprehensive, and reusable one. I will be using styled components for the styles, but you can use any other styling library you prefer.
Without animation
First, we will go with simple example with no animations. Just a state isOpen which determines if the Modal is mounted or not.
Adding enter animation
Adding exit animation
We will need a state isClosing that refers to when the user closed the modal. This will be accompanied by a setTimeout, where, after a certain amount of time, we will set isOpen to false.
Then, we will pass isClosing to the Modal component.
Increasing the readability
If we want the code to be more readable and easier to understand, we can do the following:
Pass isOpen to Modal
Pass the same prop to Content styled component
And handle the animations
Creating a custom hook useDisclosure
Probably, we will need this same logic for future components. In that case, it would be a good practice to create a custom hook so that we can reuse it. Let's create a custom hook called useDisclosure.
and consumit it on App:
Extending useDisclosure
For a more comprehensive and reusable solution, we can extend the useDisclosure hook so that we have different transition stages:
unmounted
mounting
mounted
unmounting
Note that I renamed isClosing to isUnmounting. I think it's more appropriate.
Something that is worth to mention, we used 150ms for the transition between each phase for useDisclosure hook, and we also used the same value for the animation-time for the animations inside Modal. Ideally we save this value inside a variable to make sure it is the same in all the places.
Other alernatives
Without unmounting the component
Note that we are doing
Another alternative I have seen is to never unmount the component by doing
and depending on the isOpen property, we add the styles (using pointer-events: none)
Personally, I think this is not a good approach in terms of efficiency. We should only have mounted in the component tree what we are currently viewing.
Using onAnimationEnd
When a CSS animation is applied to an element and that animation finishes, the onAnimationEnd event is triggered. We can use this event to execute onClose.
Again, I don't think it's the best way to do an exit animation. If we remove the animation in the future, the modal won't close.