What Are Vue Slots?
Slots serve as placeholder elements in component templates that parent components can fill with custom content. This mechanism enables component creators to define flexible content areas that consumers can customize without modifying the component's internal logic. Unlike props, which transmit data values, slots transmit entire template fragments, allowing for dynamic and contextual content injection at render time.
The slot mechanism in Vue is directly inspired by the native Web Component <slot> element specification, but Vue extends this concept with additional capabilities including scoped slots, dynamic slot names, and advanced composition patterns that make component design more flexible and powerful.
As part of our comprehensive approach to web development services, Vue slots represent an essential pattern for building scalable component libraries that maintain clean separation between component logic and presentation.
Understanding when to use slots vs props for component flexibility
Content vs Data
Props transmit data values, while slots transmit template content for flexible rendering.
Component Composability
Slots enable wrapper components that maintain consistent styling while accepting varied content.
Layout Control
Named slots allow precise content placement within component structures.
Child-to-Parent Communication
Scoped slots enable reverse data flow for powerful renderless component patterns.
Default Slots
The default slot provides a simple mechanism for passing a single content fragment into a component. When a component includes a <slot> element without a name attribute, it creates a default slot that accepts any content not assigned to named slots.
The button component below demonstrates this pattern. The <slot>Submit</slot> element renders "Submit" as fallback content when no content is provided, but accepts any HTML, components, or text when the parent component supplies it.
This flexibility makes default slots ideal for wrapper components like buttons, cards, and containers that need to accommodate varied content while maintaining consistent styling and behavior. For teams working across frameworks, understanding how slots compare to similar patterns in React and other frameworks helps build technology-agnostic component architecture skills.
Render Scope
Understanding render scope is essential for working effectively with slots. Slot content is compiled and evaluated in the scope where it is defined--the parent component--not the child component providing the slot outlet.
Expressions in slot content have access to the parent component's data, methods, and computed properties, but cannot directly access the child component's internal state. The first example below works correctly, accessing message from the parent. The second reference to childData would fail because that data exists only in the child component's scope.
This scope behavior follows JavaScript's lexical scoping principles and ensures that component content remains predictable and debuggable. When child component data needs to be exposed to slot content, scoped slots provide the solution, which we explore in detail later in this guide.
1<template>2 <button class="btn">3 <slot>Submit</slot>4 </button>5</template>6 7<script>8export default {9 // Component logic10}11</script>1<template>2 <Child>3 {{ message }} <!-- Works: accesses parent's data -->4 {{ childData }} <!-- Error: childData not in parent scope -->5 </Child>6</template>7 8<script>9export default {10 data() {11 return {12 message: 'Hello from parent',13 items: [1, 2, 3]14 }15 }16}17</script>Named Slots
Named slots enable components to accept and organize multiple content fragments, each targeting a specific slot outlet. This capability proves essential for layout components that need to structure content into distinct regions such as headers, footers, sidebars, and primary content areas.
The Card component below defines three slots: a named "header" slot, a default slot for main content, and a named "footer" slot. Each slot can have its own fallback content that renders when no content is provided.
Parent components populate named slots using the v-slot directive or its convenient shorthand #. The template element wraps slot content, explicitly indicating which slot each piece of content targets. Unassigned content automatically flows into the default slot.
Dynamic Slot Names
Vue 3 supports dynamic slot names through expressions, valuable when building configurable layout systems where slot names depend on component state or configuration.
This pattern proves valuable when building themeable component libraries or layout systems where different sections need to be configured at runtime based on user preferences or application state. Our front-end development team regularly implements these patterns when building design systems that require runtime customization.
1<template>2 <div class="card">3 <header class="card-header">4 <slot name="header">Default Header</slot>5 </header>6 <main class="card-body">7 <slot></slot>8 </main>9 <footer class="card-footer">10 <slot name="footer">Default Footer</slot>11 </footer>12 </div>13</template>1<template>2 <Card>3 <template #header>4 <h2>Card Title</h2>5 </template>6 7 <p>Main content goes here.</p>8 9 <template #footer>10 <span class="meta">Last updated 5 min ago</span>11 </template>12 </Card>13</template>1<template>2 <Layout>3 <template #[dynamicHeader]>Header Content</template>4 <template #[dynamicSidebar]>Sidebar Content</template>5 </Layout>6</template>7 8<script>9export default {10 data() {11 return {12 dynamicHeader: 'header',13 dynamicSidebar: 'sidebar'14 }15 }16}17</script>Scoped Slots
Scoped slots enable child components to expose their internal data and methods to the parent component's slot content. This reverse data flow enables powerful patterns for creating renderless components, data presentation components, and flexible UI patterns that separate data logic from rendering logic.
How Scoped Slots Work
When a component includes attributes on its <slot> element, those attributes become available as scope variables to the parent component's slot content. The UserList component below demonstrates this pattern by passing each user object and their index as slot props.
Parent components access the scoped data using v-slot with destructuring syntax, extracting only the fields needed for rendering. The example shows how to access user data and apply conditional styling based on the user's role.
Practical Scoped Slot Patterns
Renderless Data Components: Components that handle data fetching and state while delegating rendering entirely to parent-provided templates. This pattern creates highly reusable components that handle data logic while giving parents full control over presentation.
Conditional Slot Rendering: Components that expose slots for different states like loading, error, and success. The parent can provide different content for each state while the child component manages the underlying logic.
Scoped Slots in Vue 3 Composition API
Vue 3's Composition API provides enhanced patterns with TypeScript support. The useSlots() composable and <script setup> syntax enable more concise component definitions while maintaining full type safety for slot props.
This modern approach integrates naturally with Vue 3's type system, improving developer experience through better IDE integration and compile-time type checking for slot props and exposed data. For teams implementing complex state management patterns, combining scoped slots with our AI automation services can create intelligent, adaptive UI components that respond to changing data conditions.
1<template>2 <div class="user-list">3 <slot4 v-for="user in users"5 :user="user"6 :index="user.id"7 ></slot>8 </div>9</template>10 11<script>12export default {13 data() {14 return {15 users: [16 { id: 1, name: 'Alice', role: 'Admin' },17 { id: 2, name: 'Bob', role: 'Editor' }18 ]19 }20 }21}22</script>1<UserList>2 <template #default="{ user, index }">3 <div class="user-item" :class="{ 'admin': user.role === 'Admin' }">4 #{{ index }} - {{ user.name }} ({{ user.role }})5 </div>6 </template>7</UserList>1<script setup>2import { ref, useSlots } from 'vue'3 4const users = ref([5 { id: 1, name: 'Alice', email: '[email protected]' },6 { id: 2, name: 'Bob', email: '[email protected]' }7])8 9const slots = useSlots()10 11// Access scoped slot data programmatically12const defaultSlot = slots.default13</script>14 15<template>16 <table>17 <thead>18 <tr><th>ID</th><th>Name</th><th>Email</th></tr>19 </thead>20 <tbody>21 <tr v-for="user in users" :key="user.id">22 <slot name="row" :user="user">23 <td>{{ user.id }}</td>24 <td>{{ user.name }}</td>25 <td>{{ user.email }}</td>26 </slot>27 </tr>28 </tbody>29 </table>30</template>Fallback Content
Fallback content provides default markup that renders when a parent component doesn't provide slot content. This feature makes components robust and usable without requiring content in every instance, supporting graceful degradation for optional features.
The Modal component below demonstrates fallback content across all three slots. The header slot defaults to a basic heading, the default slot shows "No content provided," and the footer slot provides a confirmation button.
Fallback content renders only when no content is provided for that slot. When a parent provides content, the fallback is entirely replaced. This pattern proves particularly useful for:
- Optional features that work without content
- Default actions for form buttons
- Graceful degradation in component libraries
- Prototyping before final content is ready
This approach reduces boilerplate in consuming components while ensuring every component instance remains functional and visually complete.
1<template>2 <div class="modal-overlay">3 <div class="modal-content">4 <header class="modal-header">5 <slot name="header">6 <h3>Default Title</h3>7 </slot>8 <button class="close-btn" @click="$emit('close')">×</button>9 </header>10 <main class="modal-body">11 <slot>12 <p>No content provided.</p>13 </slot>14 </main>15 <footer class="modal-footer">16 <slot name="footer">17 <button @click="$emit('confirm')">OK</button>18 </slot>19 </footer>20 </div>21 </div>22</template>Performance Considerations
Understanding slot performance helps optimize Vue applications effectively, especially in large-scale applications with complex component trees and frequent updates.
Slot Re-rendering: Slot content re-renders when the parent component updates, not when the child component updates--unless the child exposes reactive data through scoped slots. This behavior means default slots can offer performance advantages for static content regions that don't need to react to child component changes.
Scoped Slot Reactivity: When using scoped slots with reactive data, changes to the child component's data trigger slot content updates. Design components to minimize unnecessary reactivity in slot props to avoid excessive re-renders.
v-memo Optimization: Vue 3's v-memo directive can optimize slot content that doesn't need frequent updates by memoizing the rendering result based on dependency arrays.
Best Practices
Following consistent best practices ensures maintainable component libraries that scale gracefully:
-
Naming Conventions: Use clear, descriptive slot names that indicate purpose rather than position.
name="actions"is preferable toname="right-side"as it describes the content's semantic role. -
Documentation: Document slot props and their types, especially for public component libraries. Consider using documentation tools like Vue Styleguidist or Storybook for comprehensive documentation.
-
TypeScript Support: Use TypeScript interfaces for slot props to enable IDE autocompletion and type checking, improving developer experience and reducing runtime errors.
-
Testing: Test slot content rendering in component tests using proper slot mounting patterns to ensure components handle various content scenarios correctly.
For teams building complex Vue applications, these patterns integrate seamlessly with our React development services and broader front-end development offerings, ensuring consistent component architecture across technology stacks.
Frequently Asked Questions
What is the difference between slots and props in Vue?
Props transmit data values to child components, while slots transmit template content. Use props for data/configuration and slots for content customization and layout flexibility.
Can I use slots with Vue 3 Composition API?
Yes, Vue 3 fully supports slots with the Composition API. Use the useSlots() composable and define components with <script setup> for optimal TypeScript support and cleaner syntax.
What are scoped slots in Vue?
Scoped slots allow child components to expose their internal data to the parent component's slot content through attributes on the <slot> element, enabling powerful renderless component patterns.
How do I pass multiple content areas in one component?
Use named slots with the name attribute on <slot> elements. Populate them using v-slot:slotName or the convenient #slotName shorthand in parent templates.
What is fallback content in Vue slots?
Fallback content is default markup placed inside a <slot> element that renders when no content is provided. It makes components robust by providing sensible defaults.
Do slots affect component performance?
Default slots render when parent updates; scoped slots re-render when child data changes. Use v-memo and minimize reactivity in slot props for optimization.
Sources
- Vue.js Official Documentation - Slots - The authoritative source for Vue slots, covering all slot types, render scope, named slots, scoped slots, and the v-slot directive.
- LogRocket Blog - A Deep Dive Into Vue Slots - Comprehensive tutorial covering slot mechanisms, named slots, scoped slots, and practical examples for building reusable components.
- MDN Web Docs - Slot Element - Web Component slot reference providing context for Vue's slot implementation.