Telerik blogs

Have you been struggling checking whether or not a slot is empty in Vue 3? This breaking change has a lot of people grasping for the best solution, so let's explore one together.

I have the privilege to work in a company that allows me to be an early adopter of technology, among them Vue 3. When Vue 3 was barely making its way out of beta, I quickly started working on the migration from our entire codebase from Vue 2 to the shiny new version.

At this point in time, the compat-build (the migration build) was nothing short of a disaster, so I opted for ripping off the bandage and just migrating everything cold turkey. This, as you can imagine, came with a few hiccups.

One of the most complex workarounds was to find a way to find a way to determine if the content of a slot being received in a component was empty. In Vue 2, if you remember, this was an absolute breeze:

<div v-if="this.$slots.mySlot">
   <p>Some unrelated content to the slot or extra markup</p>
   <slot name="mySlot" />
</div>

A simple if check would result in a falsey value if the content of mySlot was empty, and we could all move on to better things. In Vue 3 this is not as straightforward. So I set myself the task to find the culprit and, alas, finally figured out where the change in the way that Vue is internally checking for this.

I was not surprised some other people had already run into a similar problem, so I found a way to articulate the problem and created an issue for this problem. The problem sadly did not end there, since—as Posva quickly let me know—it was near impossible to reach a consensus of what “empty” would mean if the core team was to at some point consider the possibility of creating an official isEmptySlot checking function.

Through lots of trial and error, and the help of amazing minds in the community, we came up with an elegant-enough solution that we turned into a composable. But I was intrigued to see that I was still getting a lot of notifications for an issue that has been closed for months, so I’ve decided to share mine and my team’s findings and code with a brief explanation.

To the codemobile!

batman and robin gif - ready to move out

import { computed, Comment, Fragment, Text } from 'vue'

/**
 * Determines whether a slot is empty for Vue 3: https://github.com/vuejs/vue-next/issues/3056
 * @param {Function} slot - The slot $slot.name
 * @returns {Boolean}
 */

// Adapted from https://github.com/vuejs/vue-next/blob/ca17162e377e0a0bf3fae9d92d0fdcb32084a9fe/packages/runtime-core/src/helpers/renderSlot.ts#L77

function vNodeIsEmpty (vnodes) {
  return vnodes.every(node => {
    if (node.type === Comment) return true
    if (node.type === Text && !node.children.trim()) return true
    if (
      node.type === Fragment &&
      vNodeIsEmpty(node.children)
    ) {
      return true
    }

    return false
  })
}

/**
 * Returns true if a slot has no content
 * @param {Function | Object} slot a Vue 3 slot function or a Vue 2 slot object
 * @returns {Boolean}
 */
export const isEmpty = slot => {
  if (!slot) return true

  // if we get a slot that is not a function, we're in vue 2 and there is content, so it's not empty
  if (typeof slot !== 'function') return false

  return vNodeIsEmpty(slot())
}

export default function ({
  slot
}) {
  const slotIsEmpty = computed(() => isEmpty(slot))

  return {
    slotIsEmpty
  }
}

The composable takes an object parameter with a single property, slot which you can acquire with the useSlots function like so.

import { useSlots } from 'vue'

const slots = useSlots()
const { slotIsEmpty } = SetupEmptySlotCheck({ slot: slots.mySlot })

// template
<div v-if="slotIsEmpty"> No slot content! </div>

In return, you get an slotIsEmpty computed that will be either true/false depending on whether the content of the slot is empty or not.

In order to determine what an empty slots constitutes, we made the following assumptions.

A slot is empty if:

• It only includes HTML comments
• It only includes empty strings
• It includes several children, and all of them are themselves empty

If you want to also look at our unit tests, I’ve set up a public gist with the code.

I hope this clears out any questions and helps other teams struggling with this breaking change.


Vue
About the Author

Marina Mosti

Marina Mosti is a frontend web developer with over 18 years of experience in the field. She enjoys mentoring other women on JavaScript and her favorite framework, Vue, as well as writing articles and tutorials for the community. In her spare time, she enjoys playing bass, drums and video games.

Related Posts

Comments

Comments are disabled in preview mode.