JAVASCRIPT
Advanced Component Composition with Scoped Slots
Enhance component reusability and flexibility in Vue 3 by mastering scoped slots, allowing parent components to customize child component rendering with access to child data.
// src/components/DataList.vue (Child Component)
<template>
<div class="data-list">
<h3>{{ title }}</h3>
<ul>
<li v-for="item in items" :key="item.id">
<!-- Scoped slot: exposing 'item' and 'index' data -->
<slot :item="item" :index="index">
{{ item.name }} <!-- Fallback content -->
</slot>
</li>
</ul>
</div>
</template>
<script setup>
import { defineProps } from 'vue';
defineProps({
title: String,
items: {
type: Array,
required: true
}
});
</script>
// src/App.vue (Parent Component)
<template>
<div id="app">
<h1>Product List</h1>
<DataList :items="products" title="Available Products">
<!-- Using v-slot to access scoped slot props -->
<template v-slot="{ item, index }">
<div class="product-item">
<span>{{ index + 1 }}. <strong>{{ item.name }}</strong> - ${{ item.price }}</span>
<span v-if="item.inStock" class="status-badge">In Stock</span>
<span v-else class="status-badge out-of-stock">Out of Stock</span>
</div>
</template>
</DataList>
<hr />
<h1>User List (default rendering)</h1>
<DataList :items="users" title="Registered Users" />
</div>
</template>
<script setup>
import { ref } from 'vue';
import DataList from './components/DataList.vue';
const products = ref([
{ id: 1, name: 'Laptop', price: 1200, inStock: true },
{ id: 2, name: 'Mouse', price: 25, inStock: false },
{ id: 3, name: 'Keyboard', price: 75, inStock: true },
]);
const users = ref([
{ id: 101, name: 'Alice Smith' },
{ id: 102, name: 'Bob Johnson' },
]);
</script>
// Basic CSS for demonstration (optional)
<style>
.product-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #eee;
}
.status-badge {
font-size: 0.8em;
padding: 4px 8px;
border-radius: 4px;
background-color: #e0ffe0;
color: #007000;
}
.status-badge.out-of-stock {
background-color: #ffe0e0;
color: #700000;
}
</style>
How it works: Scoped slots are a powerful Vue 3 feature allowing a child component to pass data back to its parent's slot content, enabling highly flexible and reusable components. In this example, `DataList.vue` iterates over a list and exposes each `item` and its `index` to its default slot. The parent `App.vue` consumes this slot using `<template v-slot="{ item, index }">`, gaining access to the child's data to render completely customized content for each list item, while `DataList` remains responsible for the list structure.