Scoped slots are a feature in Vue.js that take your component design to the next level by allowing for greater flexibility in your templates. While regular slots are great for content distribution, scoped slots empower you to access data and functionality from the parent component, making your components significantly more versatile and reusable.
What Are Scoped Slots?
Before diving into real-world implementations, let's clarify what scoped slots are. In simple terms, a scoped slot is a slot that allows you to pass data from a child component back to the parent component. Unlike regular slots, which only allow you to inject content into a component, scoped slots enable you to bind data to the slot and use that data within the parent’s template.
Regular Slot vs. Scoped Slot
To better illustrate the difference, let’s look at a simple example.
Regular Slot Example
<template> <div> <my-component> <p>This is regular slot content!</p> </my-component> </div> </template> <script> export default { components: { MyComponent: { template: `<div><slot></slot></div>` } } } </script>
In this example, the content of the <p>
tag is passed into MyComponent
without any access to the parent’s data.
Scoped Slot Example
Now, let’s see how scoped slots change the game:
<template> <div> <my-component> <template v-slot:default="slotProps"> <p>{{ slotProps.message }}</p> </template> </my-component> </div> </template> <script> export default { components: { MyComponent: { data() { return { message: 'Hello from MyComponent!' }; }, template: `<div><slot :message="message"></slot></div>` } } } </script>
In this updated example, MyComponent
passes the message
data to the parent through the scoped slot. The parent component can then use that data wherever needed.
When to Use Scoped Slots
Scoped slots are especially useful when:
- You need to customize the rendering of child components using data derived from the child.
- You are creating higher-order components that must remain flexible for different use cases.
Let's explore a practical example involving a list item renderer.
Dynamic List Rendering with Scoped Slots
Say we have a simple list component that should render various item templates based on the type of data passed to it.
<template> <ul> <li v-for="item in items" :key="item.id"> <slot :item="item"></slot> </li> </ul> </template> <script> export default { props: { items: { type: Array, required: true } } } </script>
We can utilize this component in various ways by leveraging scoped slots:
<template> <div> <item-list :items="userList"> <template #default="{ item }"> <div> <strong>{{ item.name }}</strong> - {{ item.email }} </div> </template> </item-list> <item-list :items="productList"> <template #default="{ item }"> <div> <em>{{ item.title }}</em> - \${{ item.price }} </div> </template> </item-list> </div> </template> <script> export default { data() { return { userList: [ { id: 1, name: 'John Doe', email: 'john@example.com' }, { id: 2, name: 'Jane Doe', email: 'jane@example.com' } ], productList: [ { id: 1, title: 'Laptop', price: 999 }, { id: 2, title: 'Smartphone', price: 499 } ] }; } } </script>
In this setup, the item-list
component serves as a reusable list renderer, with different rendering based on the type of data provided thanks to the scoped slot.
Conclusion
Through scoped slots, you can achieve a high level of reusability and flexibility in your Vue.js components. The key takeaway is that with scoped slots, you’re not just passing content—you’re passing data and functionality that can be used in a more dynamic fashion. By leveraging this powerful feature, you can craft more sophisticated, maintainable, and reusable components in your Vue.js applications. Happy coding!