Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

sididev's avatar

Modal transition not working

Hi, this is the second time I have this problem which is really annoying me. I created a modal component which I use in the main component. The problem is that the modal transition wasn't working until I added the appear . I jumped for joy but the transition only works if I open the modal but when I close it's like there is no transition class to close.

this is my modal component content:

<template>
    <div
        v-if="show"
        class="fixed top-0 left-0 w-full h-full flex items-center justify-center bg-gray-900 bg-opacity-60 z-20"
    >
        <div class="fixed inset-0 bg-transparent" @click="zoomOutModal"></div>
        <Transition name="slide-fade" appear>
            <div
                class="max-w-lg bg-[#151f32] w-full p-5 rounded-lg shadow-lg z-30"
                :class="{
                    'transition-all scale-105 ease-linear duration-700': zoomIn,
                }"
            >
                <h2 class="text-lg font-medium mb-3 text-center">
                    <slot>Titre du modal</slot>
                </h2>
                <slot name="content"></slot>
            </div>
        </Transition>
    </div>
</template>

<script setup>
import { ref } from 'vue'
import Buttons from '@/Components/Buttons.vue'

const show = ref(true)
const zoomIn = ref(false)

const zoomOutModal = () => {
    zoomIn.value = true
    setTimeout(() => {
        zoomIn.value = false
    }, 300)
}
</script>

<style>
.slide-fade-enter-active,
.slide-fade-leave-active {
    transition: all 0.3s ease-out;
}

.slide-fade-enter-from {
    transform: translateY(100vh);
    opacity: 0;
}

.slide-fade-leave-to {
    transform: translateY(0vh);
    opacity: 0;
    transition: all 0.3s ease-out;
}
</style>

and this is my main content :

<template>
....
....
<div class="mt-6">
    <Buttons @click="showModal = true"> Ajouter Type</Buttons>
    <Modal v-if="showModal" @close="showModal = false">
        Add Type
        <template v-slot:content>
            <form
                @keydown.enter="sumitAddType"
                @submit.prevent="sumitAddType"
                class="space-y-3"
            >
                <input
                    class="px-3 py-2 bg-dark-item-bg text-white border-none rounded-xl w-full placeholder-gray focus:focus:ring-blue/30"
                    type="text"
                    placeholder="Tapez le text le nom"
                    v-model="modalForm.name"
                />
                <div v-if="errors" class="mt-5 space-y-2">
                    <div
                        v-for="error in errors"
                        v-text="error"
                        class="text-red text-xs"
                    ></div>
                </div>
                <div class="flex gap-4">
                    <CancelButtons @click="showModal = false"
                        >Annuler</CancelButtons
                    >

                    <Buttons :disabled="modalForm.processing">
                        <div v-if="modalForm.processing">
                            <Spinner />
                        </div>
                        <div v-else>Ajouter</div>
                    </Buttons>
                </div>
            </form>
        </template>
    </Modal>
</div>
....
....
</template>

Thank you in advance for your help.

0 likes
5 replies
lbecket's avatar

You are missing the leave-active transition class. When the modal is closed, the modal component is removed from the DOM and that's why there's no transition class to close. To fix this, you should add the slide-fade-leave-active class to the modal component.

Something like this:

<style>
.slide-fade-enter-active,
.slide-fade-leave-active {
    transition: all 0.3s ease-out;
}

.slide-fade-enter-from {
    transform: translateY(100vh);
    opacity: 0;
}

.slide-fade-leave-to {
    transform: translateY(0vh);
    opacity: 0;
}

.slide-fade-leave-active {
    transition: all 0.3s ease-out;
}
</style>
sididev's avatar

@lbecket Don't care about zoomIn it for modal when user click outside the modal it will zoom in and zoom out the modal. I have already viewed this video. but nothing changes. I have almost exactly the same code.

My modal component :

<script setup>
import { ref } from 'vue'

defineProps({
    show: Boolean,
})

const zoomIn = ref(false)

const zoomOutModal = () => {
    zoomIn.value = true
    setTimeout(() => {
        zoomIn.value = false
    }, 300)
}
</script>
<template>
    <div
        v-if="show"
        class="fixed top-0 left-0 w-full h-full flex items-center justify-center z-20"
    >
        <div
            class="fixed inset-0 bg-gray-600 bg-opacity-60"
            @click="zoomOutModal"
        ></div>
        <Transition name="slide-fade" appear>
            <div
                class="max-w-lg bg-[#151f32] w-full p-5 rounded-lg shadow-lg z-30"
                :class="{
                    'transition-all scale-105 ease-linear duration-700': zoomIn,
                }"
            >
                <h2 class="text-lg font-medium mb-3 text-center">
                    <slot>Titre du modal</slot>
                </h2>
                <slot name="content"></slot>
            </div>
        </Transition>
    </div>
</template>

<style lang="scss">
.slide-fade-enter-active,
.slide-fade-leave-active {
    transition: all 0.3s ease-out;
}

.slide-fade-enter-from {
    transform: translateY(100vh);
    opacity: 0;
}

.slide-fade-leave-to {
    transform: translateY(0vh);
    opacity: 0;
}

.slide-fade-leave-active {
    transition: all 0.9s ease-out;
}
</style>
sididev's avatar

@lbecket My Index.vue file

<template>
    <Button @click="showModal = true">Open Modal</Buttons>
    <Modal :show="showModal">
            Add Type
            <template v-slot:content>
                <form
                    @keydown.enter="sumitAddType"
                    @submit.prevent="sumitAddType"
                >
                    <input
                        class="px-3 py-2 bg-dark-item-bg text-white border-transparent rounded-xl w-full placeholder-gray focus:focus:ring-blue/30"
                        :class="{ 'border-red': errors.name }"
                        type="text"
                        placeholder="Tapez le text le nom"
                        v-model="modalForm.name"
                    />
                    <div
                        v-if="errors"
                        class="mt-2 text-red text-xs"
                        v-text="errors.name"
                    ></div>
                    <div class="flex gap-4 mt-5">
                        <CancelButtons
                            @click="
                                ;(showModal = false), (errors = {})
                            "
                            >Annuler</CancelButtons
                        >
                        <Buttons :disabled="modalForm.processing">
                            <div v-if="modalForm.processing">
                                <Spinner />
                            </div>
                            <div v-else>Ajouter</div>
                        </Buttons>
                    </div>
                </form>
            </template>
        </Modal>
    </template>
    <script setup>
    
    let showModal = ref(false)
    
    </script>

Please or to participate in this conversation.