What Are Vue.js Slots?
Slots are one of Vue.js's most powerful features for creating reusable, flexible components. They provide a clean mechanism for passing template content from parent components to child components, enabling true component composition.
Unlike props, which pass data values, slots pass entire template fragments including HTML elements and even other components. This separation of concerns allows component authors to control structure while giving component consumers freedom over content.
- Content Distribution: Slots serve as placeholder outlets where parent components inject customized content
- Template Fragments: Pass entire template snippets, not just data values
- Structural Control: Child controls layout, parent controls content
The <slot> element in Vue is inspired by the native Web Component slot element but enhanced with Vue-specific capabilities like scoped slots, fallback content, and named slots.
This approach is fundamental to modern component architecture and is widely used in frontend development, UI libraries, and enterprise applications built with Vue. When building custom web applications, slots enable you to build flexible component APIs that adapt to diverse requirements.
Mastery of slots also complements knowledge of React component patterns and Next.js routing for full-stack development excellence. For complex single-page applications, slots provide a clean pattern for separating layout concerns from content delivery, enabling your backend APIs to remain focused on data while frontend components handle presentation flexibility.
Understanding slots is essential for any developer building modern Vue.js applications that require reusable, maintainable component architectures.
Default (Unnamed) Slots
The default slot is the most straightforward slot type. When a child component defines a <slot> element without a name attribute, it serves as the default slot. Any content provided by the parent component without explicit slot targeting goes into this default slot.
How Default Slots Work
- Basic syntax: Place
<slot></slot>in the child component template - Content injection: Parent provides content directly between component opening and closing tags
- Scope access: Slot content has access to parent component's data scope, not the child's
- Fallback content: Default content can be provided inside the
<slot>tags for when no content is provided
Fallback Content
When a parent doesn't provide content for a slot, the fallback content renders instead. This ensures components remain functional even when slot content isn't explicitly provided. Fallback content is particularly useful for buttons, labels, and default UI states that should appear when consumers don't customize the component.
The fallback content is static by default but can include dynamic expressions from the child component's scope, allowing for intelligent defaults that adapt to component state.
Default slots are often the first pattern developers learn when building reusable components, and they form the foundation for understanding more advanced slot patterns like named slots and scoped slots. When combined with modern state management, slots enable powerful component architectures that scale across large applications.
1<template>2 <div class="card">3 <slot></slot>4 </div>5</template>6 7<script setup>8// Fallback content renders when no slot content is provided9</script>10 11<style scoped>12.card {13 padding: 1.5rem;14 border-radius: 8px;15 background: white;16 box-shadow: 0 2px 4px rgba(0,0,0,0.1);17}18</style>1<template>2 <ChildComponent>3 <h2>Card Title</h2>4 <p>Content in default slot renders here.</p>5 </ChildComponent>6</template>7 8<script setup>9import ChildComponent from './ChildComponent.vue'10</script>1<template>2 <div class="layout">3 <header class="layout-header">4 <slot name="header"></slot>5 </header>6 <main class="layout-content">7 <slot></slot>8 </main>9 <footer class="layout-footer">10 <slot name="footer"></slot>11 </footer>12 </div>13</template>1<template>2 <BaseLayout>3 <template #header>4 <h1>Page Title Here</h1>5 </template>6 7 <p>Main content goes to the default slot.</p>8 9 <template #footer>10 <p>Footer content here</p>11 </template>12 </BaseLayout>13</template>1<script setup>2import { ref } from 'vue'3 4const users = ref([5 { id: 1, name: 'Alice', role: 'Admin' },6 { id: 2, name: 'Bob', role: 'Developer' },7 { id: 3, name: 'Carol', role: 'Designer' }8])9</script>10 11<template>12 <div class="user-list">13 <slot 14 name="item" 15 v-for="user in users" 16 :user="user"17 :index="user.id"18 ></slot>19 </div>20</template>1<template>2 <UserList>3 <template #item="{ user, index }">4 <div class="user-item">5 <span class="index">#{{ index }}</span>6 <strong>{{ user.name }}</strong>7 <span class="role">{{ user.role }}</span>8 </div>9 </template>10 </UserList>11</template>12 13<script setup>14import UserList from './UserList.vue'15</script>| Aspect | Slots | Props |
|---|---|---|
| Primary Purpose | Content injection | Data passing |
| Content Type | Template fragments (HTML, components) | Values of any type (strings, numbers, objects, functions) |
| Scope Access | Parent scope by default | Parent scope by default |
| Child Data Access | Only via scoped slots | Directly in template |
| Flexibility | High for customization | High for data variation |
| Use When | Content structure varies | Data or behavior varies |
Frequently Asked Questions
Sources
- Vue.js Official Guide - Slots - The authoritative source for Vue.js slot implementation and patterns
- OpenReplay Blog - Slots in Vue 3 - Practical examples and best practices for implementing slots in production applications