If your component accepts slots, sometimes you'll want to check if they have been provided (or not). Why? For various
reasons. You might want to add specific styles using a div
as a wrapper and ensure that you don't render it if there
is no content — slot — to display, avoiding an empty HTML element.
Hence the conditional rendering.
Check for the existence of content for a slot
Now, how do you achieve this? With the Options API, it's straightforward because all the slots of a
component are available in the object $slots
. If your component
has at least one slot, it will be available under $slots.default
. If it has more than one slot, invoking $slots
will
give you an array of VNodes
using their names as keys.
With this understanding, we can check if there is content for a slot and decide what to do.
<!-- MyComponent.vue instantiation-->
<MyComponent>
<p>Slot content</p>
</MyComponent>
<!-- MyComponent.vue -->
<template>
<div>
<h1>Slots FTW 🔥</h1>
<div v-if="$slots.default" class="">
<slot />
</div>
<slot name="one" />
<slot name="two" />
</div>
</template>
Practical Case with the Composition API
I recently encountered a scenario where I wanted to use a component recursively. The difference between implementations is that in some cases, content will be passed to its slot, and in others, it won't.
For simplicity, I have created a small demo where we have a component called TableRow.vue
that accepts a slot. Inside
the component, we can access the list of slots with
the helper useSlots
, and, with a computed property,
decide whether to render its content or not.
import { useSlots, computed } from 'vue';
const slots = useSlots()
const hasExtraContent = computed(() => !!slots.extra);
If this is the first time you've seen the !!
operator (actually, it's not an operator, it's the !
operator twice),
don't worry. The first !
converts the value into its opposite boolean version, while the second !
inverts the
boolean value. It's a modern way to convert an object to its Boolean equivalent. Boolean()
performs the same action.
Now we can use hasExtraContent
to check if the slot extra
has content.
<template>
<div class="file">
...
<div v-if="hasExtraContent">
<slot name="extra" />
</div>
...
</div>
</template>