Vue transition works for "enter" state but not for "leave" state

1.6k views Asked by At

I have a modal rendered on top of a semi-transparent backdrop. Both elements have a v-if controlled by the same variable.

Although the enter transition animation works fine, the `leave`` transition animation is ignored (it should fade out smoothly, instead it disappears instantly). Why?

Codepen

Markup:

<div id="app">
  <button @click="showModal = !showModal">Toggle Modal</button>
  
  <div v-if="showModal" class="modalBackdrop">
    <transition name="content" appear>
      <div v-if="showModal" class="modalContent">
        Modal
      </div>
    </transition>
  </div>
</div>

CSS:

.content-enter-active {
  animation: slide-up .75s;
}

.content-leave-active {
  animation: fade-out .75s;
}

@keyframes slide-up {
  0% {
    transform: translateY(100%);
  }
  100% {
    transform: translateY(0);
  }
}

@keyframes fade-out {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
2

There are 2 answers

0
Boussadjra Brahim On BEST ANSWER

It seems that the div with modalBackdrop class is disappearing before the nested div with class modalContent does its transition, so try to wrap modal Backdrop by a transition component with name backdrop which also takes the fade-out animation :

.backdrop-leave-active,.content-leave-active { /*.backdrop-leave-active is sufficient since the parent opacity is applied on children*/
  animation: fade-out .75s;
}

template :

<div id="app">
  <button @click="showModal = !showModal">Toggle Modal</button>
  <transition name="backdrop" appear>
    <div v-if="showModal" class="modalBackdrop">
      <transition name="content" appear>
        <div v-if="showModal" class="modalContent">
          Modal
        </div>
      </transition>
    </div>
  </transition>
</div>

DEMO

0
Igor Moraru On

When showModal is false, the transition element is destroyed immediately. If the only reason you use v-if="showModal" in transition parent is to disable modalBackdrop, then you can assign this class dynamically.

This is working as expected:

  <div :class="{ modalBackdrop: showModal }">
    <transition name="content" appear>
      <div v-if="showModal" class="modalContent">
        Modal
      </div>
    </transition>
  </div>