JAVASCRIPT
Creating Flexible Components with Scoped Slots in Vue 3
Design highly reusable and customizable Vue 3 components using scoped slots. Pass data from child components to parent slot content for ultimate flexibility.
// src/components/MyList.vue
<template>
<div>
<h2>{{ title }}</h2>
<ul>
<li v-for="item in items" :key="item.id">
<slot name="item" :itemData="item" :index="item.id">
<!-- Fallback content if no slot content provided -->
{{ item.name }}
</slot>
</li>
</ul>
<slot name="footer"></slot>
</div>
</template>
<script setup>
import { defineProps } from 'vue'
defineProps({
title: String,
items: Array
})
</script>
// src/App.vue
<script setup>
import MyList from './components/MyList.vue'
const productList = [
{ id: 1, name: 'Apple', price: 1.20 },
{ id: 2, name: 'Banana', price: 0.75 },
{ id: 3, name: 'Orange', price: 1.50 }
]
</script>
<template>
<MyList title="Products" :items="productList">
<template #item="{ itemData, index }">
<div :style="{ color: itemData.price > 1 ? 'red' : 'green' }">
ID: {{ index }} - {{ itemData.name }} - Price: ${{ itemData.price.toFixed(2) }}
</div>
</template>
<template #footer>
<p>End of product list.</p>
</template>
</MyList>
</template>
How it works: Scoped slots provide a powerful way to make components highly flexible and reusable. In this example, `MyList.vue` defines a `slot` named 'item' and binds `itemData` and `index` props to it. This means the parent component (`App.vue`) can access these values within its `template #item` block, allowing it to fully customize how each list item is rendered, including conditional styling or displaying specific item properties. The `footer` slot is a regular named slot, demonstrating multiple slots. This pattern promotes separation of concerns, where the `MyList` component manages the list structure, and the parent dictates the item's appearance.