JAVASCRIPT
Creating Flexible Components with Vue 3 Scoped Slots
Master Vue 3 scoped slots to build highly reusable components that allow parent components to customize and render content with child data.
// components/CardComponent.vue
<template>
<div class="card">
<header class="card-header">
<slot name="header" :title-data="title"></slot>
</header>
<div class="card-body">
<slot :item-data="data"></slot>
</div>
<footer class="card-footer">
<slot name="footer" :action-data="actions"></slot>
</footer>
</div>
</template>
<script setup>
import { ref } from 'vue';
const title = ref('Default Card Title');
const data = ref({ message: 'Default content message', count: 123 });
const actions = ref(['View', 'Edit', 'Delete']);
</script>
<style scoped>
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
margin: 15px;
max-width: 300px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.card-header {
font-weight: bold;
margin-bottom: 10px;
border-bottom: 1px solid #eee;
padding-bottom: 5px;
}
.card-body {
margin-bottom: 10px;
}
.card-footer {
font-size: 0.9em;
color: #666;
border-top: 1px solid #eee;
padding-top: 5px;
}
</style>
// App.vue
<template>
<h1>Scoped Slots Example</h1>
<CardComponent>
<!-- Default slot with scoped data -->
<template v-slot="{ itemData }">
<p>Custom Body: {{ itemData.message }} (Count: {{ itemData.count }})</p>
</template>
<!-- Named header slot with scoped data -->
<template v-slot:header="{ titleData }">
<h2 style="color: purple;">{{ titleData }} - Custom Header</h2>
</template>
<!-- Named footer slot with scoped data -->
<template #footer="{ actionData }">
<p>Available Actions: <span v-for="action in actionData" :key="action">{{ action }} | </span></p>
</template>
</CardComponent>
<CardComponent>
<!-- Another example with different content, using default data if no slot props are needed -->
<template v-slot>
<p>This card only has a custom body without using scoped slot data.</p>
</template>
<template #header>
<h3 style="color: orange;">Simple Card</h3>
</template>
<template #footer>
<p>No actions here.</p>
</template>
</CardComponent>
</template>
<script setup>
import CardComponent from './components/CardComponent.vue';
</script>
How it works: This snippet demonstrates the power of Vue 3's scoped slots for creating highly flexible and reusable components. `CardComponent.vue` defines multiple slots (default, named 'header', 'footer') and passes internal data (like `title`, `data`, `actions`) to these slots as 'slot props'. In `App.vue`, the parent component consumes `CardComponent` and uses `<template v-slot="{ ... }">` (or its shorthand `#slotname="{ ... }"`) to access and render this child-provided data within the slot's content, allowing for full customization of the component's inner structure while retaining its layout and styling.