JAVASCRIPT
Creating Flexible Layout Components with Vue 3 Scoped Slots
Master Vue 3 scoped slots to build highly reusable components that let parent components define how specific parts of the child's content are rendered, passing data back.
// CardComponent.vue
<template>
<div class="card">
<div class="card-header">
<slot name="header" :title="headerTitle">Default Header</slot>
</div>
<div class="card-body">
<slot :contentData="bodyContent">Default Body Content</slot>
</div>
<div class="card-footer">
<slot name="footer">Default Footer</slot>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const headerTitle = ref('My Awesome Card');
const bodyContent = ref('This is the main content of the card.');
</script>
<style scoped>
.card { border: 1px solid #ccc; padding: 10px; margin: 10px; border-radius: 8px; }
.card-header { font-weight: bold; margin-bottom: 5px; background-color: #f0f0f0; padding: 5px; }
.card-body { border-top: 1px solid #eee; border-bottom: 1px solid #eee; padding: 10px 0; }
.card-footer { font-size: 0.8em; color: #666; margin-top: 5px; }
</style>
// App.vue (Parent Component)
<template>
<CardComponent>
<!-- Named Slot for header, accessing slot props -->
<template #header="{ title }">
<h2>{{ title }} - Custom Header!</h2>
</template>
<!-- Default Slot (implicitly 'default'), accessing slot props -->
<template #default="{ contentData }">
<p style="color: blue;">Overridden body: {{ contentData.toUpperCase() }}</p>
<button @click="alert('Action!')">Click Me</button>
</template>
<!-- Named Slot for footer -->
<template #footer>
<small>Posted 2 days ago.</small>
</template>
</CardComponent>
<CardComponent>
<!-- No slots provided, default content will render -->
</CardComponent>
</template>
<script setup>
import CardComponent from './CardComponent.vue';
</script>
How it works: This example showcases Vue 3's powerful scoped slots, which allow child components to provide data to their slot content, which is rendered by the parent component. `CardComponent` defines named slots (`header`, `footer`) and a default slot, passing data like `title` and `contentData` to them. The parent (`App.vue`) then uses `<template #slotName="{ propName }">` to receive this data and render custom content, enabling highly flexible and reusable UI components.