I created a custom Vue 3 directive v-visibility
to mimic the behavior of the native v-show
and v-if
but for the visibility
CSS property.
app.directive('visibility', (el: HTMLElement, binding: DirectiveBinding<boolean>) => {
el.style.visibility = binding.value ? 'visible' : 'hidden'
})
The problem is that when the binding value is false
, the element's styles are updated only after it's been mounted and therefore, there is a flash because it is always visible at first.
I tried using the non-shorthand directive syntax to set the style during created
as well as beforeMount
but the result was the same.
Am I doing something wrong or is it just not possible to do this with a custom directive?
Edit: Here is a reproduction: https://stackblitz.com/edit/nuxt-starter-atssfn?file=plugins%2Fv-visibility.ts
Edit 2: I should have mentioned that I'm using Nuxt 3 with SSR.
I figured it out. After @EstusFlask mentioned that the problem is with SSR, I checked what the Vue documentation had to say about custom directives & SSR and found out that I need to use the getSSRProps hook.
This is the updated directive (the whole Nuxt plugin), which works fine with SSR:
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('visibility', {
beforeMount: handleVisibility,
updated: handleVisibility,
getSSRProps: (binding) => {
return {
style: {
visibility: binding.value ? 'visible' : 'hidden',
},
}
},
})
})
const handleVisibility = (el: HTMLElement, binding: DirectiveBinding<boolean>) => {
el.style.visibility = binding.value ? 'visible' : 'hidden'
}