Slots

Back

Loading concept...

Vue.js Slots: The Magic Gift Boxes 🎁

The Story of the Magic Mailbox

Imagine you have a magic mailbox. This mailbox is special because whatever you put inside it appears somewhere else—inside a friend’s house, exactly where they want it!

In Vue.js, Slots work just like this magic mailbox. A parent component can send content (like letters, gifts, or surprises) through slots, and the child component decides where to display them.


What Are Slots?

Think of a slot as a placeholder or an empty box inside a component that says:

“Hey! Put something here, please!”

The parent component fills that box with whatever content it wants.

Simple Example

Child Component (MyCard.vue):

<template>
  <div class="card">
    <slot></slot>
  </div>
</template>

Parent Using It:

<MyCard>
  <p>Hello! I'm inside the card!</p>
</MyCard>

Result:

<div class="card">
  <p>Hello! I'm inside the card!</p>
</div>

The <slot> tag is like saying: “Whatever the parent puts between my tags goes HERE.”


Slot Content

Slot Content is whatever you place between a component’s opening and closing tags.

graph TD A["Parent Component"] -->|sends content| B["slot tag"] B --> C["Content Appears Here"]

Real Example

<AlertBox>
  <strong>Warning!</strong>
  <p>Your ice cream is melting!</p>
</AlertBox>

Everything between <AlertBox> and </AlertBox> is the slot content. It gets inserted where the child’s <slot> lives.


Slot Fallback Content

What if no one sends anything to your mailbox? You can have a default message waiting!

Fallback Content is what shows up when the parent doesn’t provide any slot content.

Example

Child (SubmitButton.vue):

<template>
  <button>
    <slot>Submit</slot>
  </button>
</template>

Parent Option 1 - No content:

<SubmitButton></SubmitButton>
<!-- Shows: Submit -->

Parent Option 2 - Custom content:

<SubmitButton>Save Changes</SubmitButton>
<!-- Shows: Save Changes -->

Think of it like a greeting card. The card says “Happy Birthday” by default, but you can write your own message!


The v-slot Directive

The v-slot directive is your remote control for slots. It lets you:

  • Target specific slots by name
  • Receive data from slots (scoped slots)

Basic Syntax

<template v-slot:default>
  Content goes here
</template>

Shorthand: The # Symbol

Just like @ is short for v-on, the # is short for v-slot:

<template #default>
  Content goes here
</template>

Named Slots

What if your mailbox has multiple compartments? One for letters, one for packages, one for magazines?

Named Slots let you have multiple slots with different names!

Example

Child (PageLayout.vue):

<template>
  <div class="page">
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

Parent Using It:

<PageLayout>
  <template #header>
    <h1>My Website</h1>
  </template>

  <p>Main content goes here!</p>

  <template #footer>
    <p>Copyright 2024</p>
  </template>
</PageLayout>
graph TD A["&#35;header"] --> B["Header Section"] C["Default Slot"] --> D["Main Section"] E["&#35;footer"] --> F["Footer Section"]

Key Points:

  • <slot name="header"> = named slot
  • <slot> without name = default slot
  • Use #slotName to target specific slots

Dynamic Slot Names

Sometimes you don’t know which slot to use until your app is running. That’s where Dynamic Slot Names come in!

Use square brackets [ ] to make slot names dynamic:

<template #[dynamicSlotName]>
  Content for dynamic slot
</template>

Example

<script setup>
import { ref } from 'vue'
const currentSlot = ref('header')
</script>

<template>
  <PageLayout>
    <template #[currentSlot]>
      <p>I appear in: {{ currentSlot }}</p>
    </template>
  </PageLayout>
</template>

Now changing currentSlot to 'footer' moves your content to the footer slot!

Think of it like a magic envelope that changes which mailbox compartment it goes to!


Scoped Slots

Here’s where slots get superpowers! 🦸

Normal slots are like a one-way mailbox—parent sends, child receives.

Scoped Slots are a two-way street! The child can send data back to the parent through the slot.

The Problem

Imagine a list component. The child has the data, but the parent wants to decide HOW each item looks.

The Solution: Scoped Slots

Child (FancyList.vue):

<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <slot :item="item" :index="index">
        {{ item.name }}
      </slot>
    </li>
  </ul>
</template>

Parent Using It:

<FancyList :items="fruits">
  <template #default="slotProps">
    <span>{{ slotProps.item.name }}</span>
    <span>🍎</span>
  </template>
</FancyList>
graph LR A["Child Component"] -->|sends item data| B["Scoped Slot"] B -->|parent accesses| C["slotProps.item"]

The child says: “Here’s my data. You decide how to display it!”


Slot Props

Slot Props are the pieces of data that a child component passes to its slot.

How to Pass Slot Props

Bind them on the <slot> tag like regular attributes:

<slot
  :user="currentUser"
  :isAdmin="true"
  message="Hello!"
></slot>

How to Receive Slot Props

Use v-slot with a variable name:

<template #default="props">
  <p>{{ props.user.name }}</p>
  <p>{{ props.message }}</p>
</template>

Destructuring Slot Props

Make your code cleaner by destructuring:

<template #default="{ user, message }">
  <p>{{ user.name }}</p>
  <p>{{ message }}</p>
</template>

Complete Example

Child (UserCard.vue):

<template>
  <div class="user-card">
    <slot
      :user="userData"
      :lastLogin="lastLoginDate"
      :isOnline="online">
    </slot>
  </div>
</template>

<script setup>
const userData = { name: 'Alex', age: 25 }
const lastLoginDate = '2024-01-15'
const online = true
</script>

Parent:

<UserCard>
  <template #default="{ user, isOnline }">
    <h3>{{ user.name }}</h3>
    <span :class="isOnline ? 'green' : 'gray'">
      {{ isOnline ? '🟢 Online' : '⚫ Offline' }}
    </span>
  </template>
</UserCard>

Quick Summary

Concept What It Does
Slot Placeholder for parent content
Slot Content Content placed between component tags
Fallback Content Default content if nothing provided
v-slot Directive to target slots
Named Slots Multiple slots with unique names
Dynamic Slot Names Slot names from variables
Scoped Slots Child passes data to parent
Slot Props Data passed through scoped slots

The Magic Formula

graph TD A["Parent Component"] -->|1. Provides Content| B["Slot"] B -->|2. Passes Props| C["Scoped Slot"] C -->|3. Renders Custom Content| D["Final Output"]

Remember:

  • Slots = Content placeholders
  • Named Slots = Multiple placeholders
  • Scoped Slots = Two-way data street
  • Slot Props = Data from child to parent

Now you have magic mailboxes everywhere in your Vue app! Fill them with whatever content you want, receive data back, and create flexible, reusable components.

You’re now a Slot Master! 🎓

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.