Vue Slots

Pass content from parent to child components flexibly

🎰 What are Slots?

Slots allow you to pass content from a parent component into a child component's template. They make components reusable by letting you customize content while keeping the structure consistent and organized.


<!-- Parent -->
<Card>
  <h2>My Title</h2>
  <p>My content</p>
</Card>

<!-- Child (Card.vue) -->
<div class="card">
  <slot></slot>
</div>
                                    

Slot Features

📥

Content Distribution

Pass any content to components

<Modal>
  <p>Any content</p>
</Modal>
🔄

Reusability

Same component, different content

<Button>Save</Button>
<Button>Cancel</Button>
🎨

Flexibility

Customize component internals

<Card>
  <img src="..." />
  <h3>Title</h3>
</Card>
📦

Default Content

Fallback when no content passed

<slot>
  Default text
</slot>

🔹 Basic Slot Usage

Create a simple component with a slot:

🔸 Child Component (AlertBox.vue)

<template>
  <div class="alert">
    <strong>Alert:</strong>
    <slot></slot>
  </div>
</template>

<style scoped>
.alert {
  padding: 15px;
  background: #fff3cd;
  border: 1px solid #ffc107;
  border-radius: 4px;
}
</style>

🔸 Parent Component Usage

<template>
  <div>
    <AlertBox>
      This is a warning message!
    </AlertBox>
    
    <AlertBox>
      <p>Another alert with HTML</p>
    </AlertBox>
  </div>
</template>

Output:

Alert: This is a warning message!
Alert:

Another alert with HTML

🔹 Default Slot Content

Provide fallback content when no content is passed:

<!-- Child Component (Button.vue) -->
<template>
  <button class="btn">
    <slot>Click Me</slot>
  </button>
</template>

<!-- Parent Usage -->
<template>
  <div>
    <!-- Uses default content -->
    <Button />
    
    <!-- Custom content -->
    <Button>Submit</Button>
  </div>
</template>

Output:

🔹 Named Slots

Use multiple slots with different names:

<!-- Child Component (Card.vue) -->
<template>
  <div class="card">
    <header>
      <slot name="header"></slot>
    </header>
    
    <main>
      <slot></slot>
    </main>
    
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<!-- Parent Usage -->
<template>
  <Card>
    <template #header>
      <h2>Card Title</h2>
    </template>
    
    <p>Main content goes here</p>
    
    <template #footer>
      <button>Action</button>
    </template>
  </Card>
</template>

🔹 Slot with Dynamic Content

Pass dynamic data through slots:

<template>
  <div>
    <Panel>
      <h3>{{ title }}</h3>
      <p>{{ description }}</p>
    </Panel>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import Panel from './Panel.vue'

const title = ref('Dynamic Title')
const description = ref('This content is dynamic!')
</script>

🔹 Conditional Slot Rendering

Check if slot content exists before rendering:

<template>
  <div class="container">
    <header v-if="$slots.header">
      <slot name="header"></slot>
    </header>
    
    <main>
      <slot>No content provided</slot>
    </main>
    
    <footer v-if="$slots.footer">
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

Tip: Use $slots to check if a slot has content before rendering wrapper elements.

🧠 Test Your Knowledge

What is the purpose of slots in Vue?