I have a Vue.js application where I'm using tailwind for styling. In my template, within a flex parent container, I have two child elements: one that is always rendered, and another that is conditionally rendered using v-show.
The issue is when the conditional element is rendered, it causes the first element's width to adjust automatically to accommodate the space taken by the second element within the flex container. This behavior is expected, but I'd like to add a smooth animation to the width change of the first element (for example, a sliding animation).
This is a simplified structure of my template:
<div>
<div
v-for="(group, groupName, index) in groups"
:key="groupName"
class="flex flex-row mb-2 relative"
>
<Transition
mode="in-out"
enter-from-class="-translate-x-[150%] opacity-0"
leave-to-class="-translate-x-[150%] opacity-0"
enter-active-class="transition duration-200"
leave-active-class="transition duration-200"
>
<div class="join join-vertical" v-show="buttonsVisibility[groupName]">
<!-- Conditionally rendered element -->
</div>
</Transition>
<div class="shadow-md rounded-lg collapse">
<!-- The element I would like to animate when the other element is shown/hidden -->
</div>
</div>
</div>
Current behavior:
How can I achieve an animated transition effect for the element in question? Any insights or suggestions would be greatly appreciated!
I've tried to use the Vue's built-in "Transition" component & Tailwind's different transition proprieties for the element with dynamically changing width, but with no result.
This is a viable solution to provide an animation on the given flexbox element.
<script setup>
import { ref } from 'vue'
const shown = ref(true)
</script>
<template>
<nav class="flex">
<div class="first" :class="shown && 'open'">first block</div>
<div class="second" @click="shown = !shown">second block that we do not really care about</div>
</nav>
</template>
<style>
.flex {
display: flex;
height: 50px;
}
.second {
background-color: #e9edc9;
flex: 12 0; /* set to 1 0 if you want to have an even width for the elements */
}
.first {
background-color: #caf0f8;
width: 0; /* this is important for the element to shrink */
display: hidden; /* this replaces the v-show in a better way */
transition: all 250ms ease-in-out;
}
.open {
background-color: #90e0ef;
flex: 1 0; /* where the transition happens */
}
</style>
Here is a playground in which you can fiddle with things. Nothing here is too complex and can be easily reproduced in Tailwind.
Some explanation as to what happens above:
v-show
is adding a display: none;
to the element, which is very annoying to make transitions on because of CSS constraints and without hacks, it's better to simply skip that part and use a display: hidden;
, which will produce the same visual result but is easy to apply a transition on@click="shown = !shown"
but you can totally go the @mouseenter
or @mouseleave
way too of courseflex: 12 0;
is to emulate the small width you want on the side by making the parent 12 times bigger<transition>
component, I tried to keep things simple and straight to the point so that you could transfer it to Tailwind easily:class="shown && 'open'"
, means that we should have a .open
on the element if shown
is truthy