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>&copy; 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.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs