How to add fallback content for slots in Vue?
Fallback content for a Vue slot is the template placed inside <slot> tags that renders when the parent component passes no content for that slot.
Theory
TL;DR
- Think of it like a mail slot in an apartment door: the fallback is the "No mail today" sign that shows when nothing gets delivered
- Place any template content inside
<slot>tags and Vue treats it as the default - Parent-provided content fully replaces the fallback. No merging happens
- Works with both default and named slots
- Use it for optional UI sections: empty states, default headers, generic alert messages
Quick example
<!-- Button.vue -->
<template>
<button class="btn">
<slot>Click me</slot> <!-- fallback label -->
</button>
</template>
<!-- No content passed: renders "Click me" -->
<Button />
<!-- Custom content passed: renders "Save" -->
<Button>Save</Button>The child defines what to show when the parent stays quiet. The parent can override it, but doesn't have to.
How Vue picks what to render
Vue checks whether the parent provided content for a given slot. If yes, that content renders. If not, the slot's inner template takes over. There's no blending: one wins, the other disappears entirely.
This happens at the component's mounting phase. The template compiler generates a conditional check: if slots.default exists (or slots.header for named slots), use it; otherwise render the fallback children. No extra runtime cost beyond normal vnode diffing.
When to use
- Optional layout sections (sidebars, headers) where most pages supply content but some don't
- Notification or alert components where a generic message covers the common case
- Button and input wrappers with sensible default labels
- Skip fallbacks for slots you always fill from the parent. Use props for required content instead
Most dashboard layouts I've worked on use named slot fallbacks exactly this way: the layout component defines safe defaults, and individual pages override only what they need.
Common mistakes
Expecting fallback to merge with parent content
<!-- Wrong expectation -->
<ChildComponent>
<p>Extra paragraph</p>
</ChildComponent>
<!-- Only "Extra paragraph" shows. Fallback is gone. -->Slots replace entirely. If you need both the fallback and extra content, define separate named slots.
Wrong name on a named slot
<!-- Child declares: <slot name="header"> -->
<!-- Parent uses wrong name -->
<template #head>Custom title</template>
<!-- "head" never matches "header". Fallback always shows. -->Names are case-sensitive and must match exactly. The default slot has no name attribute.
Empty template fools the fallback check
<ChildComponent>
<template #default></template>
</ChildComponent>
<!-- Vue sees a slot was provided. Fallback does not render. -->Vue considers any provided slot as filled, even if it contains nothing. This catches people trying to conditionally pass a slot from the parent.
Dynamic fallbacks and SSR
<!-- Risky in Nuxt -->
<slot><div v-if="isClient">Fallback</div></slot>If the fallback depends on client-only state, you'll get a hydration mismatch: server renders nothing, client adds the div. Keep fallbacks static or wrap them with <ClientOnly>.
Real-world usage
- Vuetify
v-card: slot fallbacks for title and action areas when parent skips them - Element Plus
el-table: default empty state message via slot fallback - Quasar
q-page: app-branded default header and drawer fallbacks - Nuxt UI: fallback notifications in global layout slots
Follow-up questions
Q: Can fallback content access the child component's data?
A: Yes. Fallback lives in the child's template scope, so it has full access to the child's reactive data, computed properties, and methods.
Q: What happens if the parent provides content for a slot that doesn't exist in the child?
A: Vue drops it. The child must declare <slot name="foo"> explicitly, otherwise the content disappears without any warning.
Q: Do scoped slots work with fallbacks?
A: Yes, with one catch. Fallback inside a scoped slot can access the slot's exposed data directly, since it runs in child scope. But if the parent overrides the slot, it must declare v-slot="{ items }" to receive that data. The fallback doesn't run at all in that case.
Q: Any performance difference between a component using fallback vs one always receiving parent content?
A: None. The check is compile-time conditional logic. Both paths generate the same number of vnode operations.
Examples
Button with default label
<!-- SubmitButton.vue -->
<template>
<button type="submit" class="btn-primary">
<slot>Submit</slot>
</button>
</template>
<!-- Usage -->
<SubmitButton /> <!-- Renders: Submit -->
<SubmitButton>Save draft</SubmitButton> <!-- Renders: Save draft -->
<SubmitButton>Delete</SubmitButton> <!-- Renders: Delete -->One component, multiple labels, zero extra props. The fallback handles the common case; callers override when they need something different.
Dashboard layout with named slot fallbacks
<!-- AppLayout.vue -->
<template>
<div class="layout">
<header>
<slot name="header">
<h1>My App</h1> <!-- generic fallback -->
</slot>
</header>
<aside>
<slot name="sidebar">
<p>No sidebar configured</p>
</slot>
</aside>
<main>
<slot>Load your content here</slot>
</main>
</div>
</template>
<!-- CRM page: overrides header and sidebar, leaves main as fallback -->
<AppLayout>
<template #header>
<h1>Customer Dashboard</h1>
</template>
<template #sidebar>
<nav>Users | Reports | Billing</nav>
</template>
<!-- No #default provided: main shows fallback text -->
</AppLayout>Each slot is independent. Providing content for #header has no effect on #sidebar or the default slot. Fallbacks fill only the gaps the parent leaves open.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.