JAVASCRIPT
Implement Reusable Layouts with Scoped Slots in Vue 3
Master scoped slots in Vue 3 to create highly flexible and reusable components, allowing parent components to customize rendered content and styling.
// MyCard.vue (Child Component)
<template>
<div class="card">
<header class="card-header">
<slot name="header" :title="cardTitle" :subtitle="cardSubtitle">
<h3>{{ cardTitle }}</h3>
</slot>
</header>
<div class="card-content">
<slot :contentData="contentDetails" :author="authorName">
<p>This is the default content of the card.</p>
</slot>
</div>
<footer class="card-footer">
<slot name="footer">
<p>© 2023</p>
</slot>
</footer>
</div>
</template>
<script setup>
import { ref } from 'vue';
const cardTitle = ref('My Awesome Card');
const cardSubtitle = ref('A subtitle passed from child');
const contentDetails = ref('Detailed information about the card content.');
const authorName = ref('Vue Expert');
</script>
<style scoped>
.card {
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
margin: 20px;
width: 300px;
font-family: sans-serif;
}
.card-header {
background-color: #f4f4f4;
padding: 15px;
border-bottom: 1px solid #eee;
}
.card-content {
padding: 15px;
}
.card-footer {
background-color: #f4f4f4;
padding: 10px;
text-align: center;
font-size: 0.8em;
color: #666;
border-top: 1px solid #eee;
}
</style>
// App.vue (Parent Component)
<template>
<MyCard>
<!-- Custom Header using Scoped Slot -->
<template #header="headerProps">
<h1>{{ headerProps.title }} <small>({{ headerProps.subtitle }})</small></h1>
</template>
<!-- Custom Default Slot Content using Scoped Slot -->
<template #default="contentProps">
<p>This content is from the parent! {{ contentProps.contentData }}</p>
<p>Written by: <strong>{{ contentProps.author }}</strong></p>
</template>
<!-- Custom Footer (normal named slot) -->
<template #footer>
<em>Updated {{ new Date().getFullYear() }}</em>
</template>
</MyCard>
</template>
<script setup>
import MyCard from './components/MyCard.vue';
</script>
How it works: This snippet illustrates how to use scoped slots for highly flexible component composition. The `MyCard` child component defines named slots (`#header`, `#footer`) and a default slot. Critically, it passes data (`cardTitle`, `contentDetails`, etc.) back to the parent using slot props (`:title="cardTitle"`). The `App.vue` parent component then accesses these props via `template #slotName="slotProps"` to render custom content, demonstrating how scoped slots enable the child to provide data while the parent dictates the rendering logic.