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.

Need help integrating this into your project?

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

Hire DigitalCodeLabs