Slots

Slots let you pass content (HTML, text, or components) from a parent into a child component, so you can create highly reusable, flexible UI components.

Let’s break them down step-by-step:
Default Slots
Named Slots
Scoped Slots


🧩 1. What Is a Slot?

A slot is a placeholder inside a component’s template where the parent can insert content.

You define a slot inside the child component, and fill it from the parent component.


🟢 2. Default Slot

The default slot is used when a component expects some content, but the slot isn’t given a name.

✅ Example

Card.vue (Child)

<template>
  <div class="card">
    <h3>Card Component</h3>
    <slot></slot> <!-- default slot -->
  </div>
</template>

<style scoped>
.card {
  border: 1px solid #ccc;
  padding: 10px;
  border-radius: 8px;
}
</style>

App.vue (Parent)

<template>
  <Card>
    <p>This content comes from the parent!</p>
  </Card>
</template>

<script setup>
import Card from './Card.vue'
</script>

🧠 Explanation:

  • The <slot></slot> in Card.vue is replaced by whatever content is placed between <Card>...</Card> in the parent.
  • If no slot content is provided, the slot is empty.

🟡 3. Default Slot with Fallback Content

You can provide default (fallback) content that appears if no slot content is passed.

✅ Example

<template>
  <div class="card">
    <slot>
      <p>No content provided. This is default fallback text.</p>
    </slot>
  </div>
</template>

🟣 4. Named Slots

Sometimes a component has multiple content areas — e.g., header, body, footer.
You can name each slot to control where the parent’s content goes.

✅ Example

Card.vue (Child)

<template>
  <div class="card">
    <header>
      <slot name="header">Default Header</slot>
    </header>

    <main>
      <slot>Default Body</slot>
    </main>

    <footer>
      <slot name="footer">Default Footer</slot>
    </footer>
  </div>
</template>

App.vue (Parent)

<template>
  <Card>
    <template #header>
      <h2>📰 Custom Header</h2>
    </template>

    <p>This is the main content from the parent.</p>

    <template #footer>
      <button>Read More</button>
    </template>
  </Card>
</template>

<script setup>
import Card from './Card.vue'
</script>

🧠 Explanation:

  • Use <template #name> (or v-slot:name) to specify which slot to fill.
  • Unnamed content goes into the default slot.

🔵 5. Scoped Slots

Scoped slots let the child send data back up to the parent’s slot content.
It’s a way for a parent to “render” child content dynamically based on child data.


✅ Example

UserList.vue (Child)

<template>
  <ul>
    <li v-for="user in users" :key="user.id">
      <!-- Provide data to the parent slot -->
      <slot :user="user">{{ user.name }}</slot>
    </li>
  </ul>
</template>

<script setup>
const users = [
  { id: 1, name: 'Alice', age: 25 },
  { id: 2, name: 'Bob', age: 30 }
]
</script>

App.vue (Parent)

<template>
  <UserList>
    <template #default="{ user }">
      <strong>{{ user.name }}</strong><em>{{ user.age }} years old</em>
    </template>
  </UserList>
</template>

<script setup>
import UserList from './UserList.vue'
</script>

🧠 Explanation:

  • The child (UserList.vue) exposes user to the slot via :user="user".
  • The parent can access that variable inside the slot template.
  • It’s like passing props from child → parent’s slot content.

⚙️ 6. Scoped Slot Syntax Options

You can use v-slot (full syntax) or the shorthand #.

<!-- full syntax -->
<template v-slot:default="{ user }">
  {{ user.name }}
</template>

<!-- shorthand -->
<template #default="{ user }">
  {{ user.name }}
</template>

<!-- shorthand when using default slot -->
<UserList v-slot="{ user }">
  {{ user.name }}
</UserList>

🧠 7. Combining Slots

You can mix default, named, and scoped slots easily.

Example:

<template>
  <div class="profile-card">
    <slot name="avatar"></slot>
    <slot :user="user"></slot> <!-- scoped slot -->
  </div>
</template>

<script setup>
const user = { name: 'Jane', role: 'Admin' }
</script>

Parent:

<ProfileCard>
  <template #avatar>
    <img src="avatar.jpg" width="50">
  </template>

  <template #default="{ user }">
    <p>{{ user.name }}{{ user.role }}</p>
  </template>
</ProfileCard>

🧱 8. Summary Table

TypeUse CaseSyntax in ChildSyntax in Parent
Default SlotInsert content<slot></slot><Child>content</Child>
Named SlotMultiple sections<slot name="header"><template #header>
Scoped SlotPass data from child to parent slot<slot :user="user"><template #default="{ user }">

🎯 When to Use Each

  • Default Slot → For basic, single-content components (e.g., cards, modals)
  • Named Slots → For multi-section layouts (e.g., header/body/footer)
  • Scoped Slots → For reusable lists/tables with flexible data rendering

Leave a Reply