Simplifying Component Composition with Slots in Vue 3

Simplifying Component Composition with Slots in Vue 3

Vue.js 3, also known simply as Vue 3, is a popular open-source JavaScript framework for building user interfaces. It is an evolution of Vue.js 2, with several significant improvements and new features. Evan You created Vue.js, and it has gained a strong following in the web development community due to its faster, smaller, more maintainable and it’s easier to target native.

What is Slots?

Slots as a powerful tool to help us create a reusable components with ease. Slots provide a mechanism for creating component templates that can receive content from the parent component. Slots enables the parent component to customize the appearance and behavior of the child component without modifying its internal structure.

Slots in Vue 3 are more flexible and powerful than in previous versions of Vue. They can be named, scoped, or even dynamic, allowing for more advanced component composition.

Default Slots

Often referred to as the nameless slot or default slot, this is the most basic kind of slot. It allows the parent component to pass content directly into the component's template.
Let me demonstrate by the following code:

<!-- ChildComponent.vue -->
<template>
  <div>
    <slot/>
  </div>
</template>

<!-- ParentComponent.vue -->
<template>
  <ChildComponent>
    <p>Lorem ipsum dolor sit amet consectetur adipiscing 
    elit magnis vehicula cum ullamcorper, nostra sociosqu curabitur 
    mollis ac netus a justo sagittis integer.</p>
  </ChildComponent>
</template>

The ChildComponent defines a default slot using the <slot/> element and the content is passed between the opening and closing tags of the ChildComponent in ParentComponent which will be rendered in place of the slot.

Named Slots

There are situations where you might want more than one slot in a single component. To do this, we can use named slots.

Named slots allow us to specify a name for a slot, then use that name in the parent component to indicate which slot the content should be inserted into.

Here’s an example of a component that uses multiple named slots:

<!-- ChildComponent.vue -->
<template>
  <div>
    <h1>My Component</h1>
    <slot name="header"></slot>
    <slot name="body"></slot>
    <slot name="footer"></slot>
  </div>
</template>

<!-- ParentComponent.vue -->
<template>
  <div>
    <ChildComponent>
      <template v-slot:header>
        <p>This is the header content</p>
      </template>
      <template v-slot:body>
        <p>This is the body content</p>
      </template>
      <template v-slot:footer>
        <p>This is the footer content</p>
      </template>
    </ChildComponent>
  </div>
</template>

The childComponent has three named slots: header, body, and footer. The parent component used these names to indicate which slot the content should be inserted into and the rendered ParentComponent Structure be like below:

  <div>
     <div>
        <h1>My Component</h1>
         <p>This is the header content</p>
         <p>This is the body content</p>
         <p>This is the footer content</p>
     </div>
 </div>

Dynamic Slots

Vue allows you to pass a dynamic value as the name of a slot. This is useful when you want to dynamically decide which slot content to render based on a condition.
This provides even greater flexibility in component composition.

Here’s an example of a component that uses Dynamic slots:

<!-- ChildComponent.vue -->
<template>
<div>
  <h1>My Component</h1>
    <slot :name="currentSlot"></slot>
</div>
</template>

<script setup>
import { ref } from "vue";
const currentSlot = ref("header");
</script>
<!-- ParentComponent.vue -->
<template>
  <ChildComponent>
    <template v-slot:[currentSlot]>
        <p>This is the {{ currentSlot }} content</p>
      </template>
  </ChildComponent>
</template>

<script setup>
import ChildComponent from './ChildComponent.vue'
const currentSlot = 'header'
</script>

In this example, the currentSlot data property is used to bind the name of the slot. In the ParentComponent, the v-slot directive is used to define the slot content, with the slot name inside square brackets and bound to the currentSlot data property.

Scoped Slots

Scoped slots take slots in Vue 3 a step further by allowing data to be passed from the child component to the parent component. This enables more dynamic and flexible composition of components. Scoped slots are defined using the <template> tag with the v-slot directive and can receive data from the child component.

Let's illustrate this with an example:

<!-- ChildComponent.vue -->
<template>
  <div>
    <slot :data="childData"></slot>
  </div>
</template>

<script setup>
const childData = "Child Data";
</script>
<!-- ParentComponent.vue -->
<template>
  <ChildComponent>
    <template v-slot="{ data }">
      <p>{{data}}</p>
    </template>
  </ChildComponent>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
</script>

In this example, the ChildComponent has a slot that receives the childData as a prop and the ParentComponent can access the childData


Conclusion

Slots enable greater component composition and customization. Whether we need to pass simple content or create complex dynamic compositions, Vue 3's slot system has got you covered. Vue’s slots take component-based development to a whole new level.
Feel free to share your thoughts and opinions and leave me a comment if you have any problems or questions. 😎😎

I hope you liked it and learned something!

Happy Coding!!