How to make transition work with “visibility” but not “display”?

I’m going to assume, for the sake of argument, that you genuinely do need to use visibility for hiding and that other potential solutions (such as opacity) won’t work in your real use case, possibly because they don’t prevent user interactions with the element.

However, the assertion in the question is slightly misleading. It isn’t really a difference between display and visibility. The real difference here is that the display case is using v-show, which includes special handling for transitions.

The current source code for v-show can be seen here:

https://github.com/vuejs/vue-next/blob/d7beea015bdb208d89a2352a5d43cc1913f87337/packages/runtime-dom/src/directives/vShow.ts

A similar approach can be used to construct a directive that uses visibility. Below is an example. It is based on the code for v-show but I’ve cut it back to just the code required for this particular use case:

const visible = {
  updated(el, { value, oldValue }, { transition }) {
    if (!value === !oldValue) {
      return
    }

    if (value) {
      transition.beforeEnter(el)
      el.style.visibility = ''
      transition.enter(el)
    } else {
      transition.leave(el, () => {
        el.style.visibility = 'hidden'
      })
    }
  }
}

Vue.createApp({
  data() {
    return {
      show: true
    };
  },
  methods: {
    toggle() {
      this.show = !this.show;
    }
  },
  directives: {
    visible
  }
}).mount('#app')
#app {
  text-align: center;
}

.tooltip-enter-active {
  transition: transform 0.4s ease-out, opacity 0.3s ease-out;
}

.tooltip-leave-active {
  transition: transform 0.35s ease-in, opacity 0.28s ease-out;
}

.tooltip-enter-from {
  transition: none;
}

.tooltip-enter-from,
.tooltip-leave-to {
  transform: translateY(-30px) scale(0.96);
  opacity: 0;
}
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<div id="app">
  <transition name="tooltip">
    <div v-visible="show">
      Using visibility
    </div>
  </transition>
  <button @click="toggle">toggle message</button>
</div>

I did also have to make a small CSS change to give the enter transition a kick:

.tooltip-enter-from {
  transition: none;
}

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top