← Back to all snippets
JAVASCRIPT

Design Flexible Components with Named and Scoped Slots

Master Vue 3's named and scoped slots to create highly customizable and reusable components, allowing parent components to control rendering and inject data into slot content.

// 1. `src/components/MyCard.vue` (Child Component defining slots)
<template>
  <div class="card">
    <header>
      <slot name="header">Default Header Content</slot>
    </header>
    <main>
      <slot :dataFromChild="message">Default Main Content</slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<script setup>
import { ref } from 'vue';
const message = ref('Hello from child!');
</script>

<style scoped>
.card {
  border: 1px solid #ccc;
  border-radius: 8px;
  padding: 15px;
  margin: 10px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
header, footer {
  padding: 10px 0;
  border-bottom: 1px dashed #eee;
}
footer {
  border-bottom: none;
  border-top: 1px dashed #eee;
}
</style>

// 2. `src/App.vue` (Parent Component using slots)
<template>
  <MyCard>
    <!-- Named Slot: header -->
    <template #header>
      <h2>My Custom Card Title</h2>
    </template>

    <!-- Default/Unnamed Slot (with scope) -->
    <template #default="slotProps">
      <p>This is the main content of the card.</p>
      <p>Data from child: <strong>{{ slotProps.dataFromChild }}</strong></p>
    </template>

    <!-- Named Slot: footer -->
    <template #footer>
      <button>Learn More</button>
      <small>Posted on {{ new Date().toLocaleDateString() }}</small>
    </template>
  </MyCard>

  <MyCard>
    <!-- Using default header content -->
    <template #default="{ dataFromChild }">
      <p>Another card without custom header or footer.</p>
      <p>Only passing child data here: <em>{{ dataFromChild }}</em></p>
    </template>
  </MyCard>
</template>

<script setup>
import MyCard from './components/MyCard.vue';
</script>
How it works: This snippet demonstrates the power of named and scoped slots in Vue 3. Named slots (`<slot name="header">`) allow a parent component to inject specific content into distinct areas of the child component's template using `<template #header>`. Scoped slots (`<slot :dataFromChild="message">`) take this a step further by allowing the child component to pass data back to the parent's slot content. The parent can then destructure this data (`#default="{ dataFromChild }"`) and use it within its injected template, enabling highly flexible and reusable component designs where the parent controls the rendering logic for specific parts of the child component while accessing its internal data.

Need help integrating this into your project?

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

Hire DigitalCodeLabs