In Vue 3, how does a parent fill a child's named slots with `v-slot` or `#`, and when does a slot's fallback content render?
answer
- outlets in the child, fragments from the parent
- unnamed outlet has a name too
- template tags carry the directive
- content between the slot tags
basics
~20 sVue's child declares outlets such as <slot name="toolbar">, and the parent targets them with <template #toolbar> (short for v-slot:toolbar). Loose content goes to the default slot. Fallback content inside <slot> renders when the parent provides nothing usable.
solid answer
~40 sThe child places outlets in its template: `<slot />` is the slot named `default`, and `<slot name="toolbar" />` is a named one. The parent passes content with `v-slot:toolbar` on a `<template>` tag, usually written `#toolbar`; any top-level content that is not inside a `<template #...>` goes to the default slot, or you can be explicit with `<template #default>`. `v-slot` is only allowed on a component tag or a `<template>`, and duplicate slot names are a compile error. Anything written *between* a `<slot>`'s tags is **fallback content**: it renders when the parent did not pass that slot, and in Vue 3.5 also when the passed content renders nothing but comments, for example because its only element has a false `v-if`. A `<DataTable>` might use this for an `#empty` slot whose fallback says *No rows*.
go deeper
Recall <slot name> in the child, <template #name> in the parent, the implicit default slot, and that text inside <slot> is the fallback.
Explain the compiler rules around v-slot placement and default content, and why comment-only content still falls back.
Treat slot names and fallbacks as part of a component's API and review changes to them like changes to props.
Set conventions for a component library's slot names and empty states so consumers can rely on consistent regions.
## Outlets and fragments A **slot** in Vue is a placeholder in a child component's template that the parent fills with its own template content. Two sides are involved: - the **child** declares **outlets** with the `<slot>` element; - the **parent** supplies **fragments** of template for those outlets when it uses the child. An outlet without a `name` attribute is implicitly named `default`. Any other outlet gets an explicit name: ```vue <!-- DataTable.vue --> <template> <div class="table"> <div class="toolbar"><slot name="toolbar" /></div> <table><slot /></table> <div v-if="rows.length === 0" class="empty"> <slot name="empty">No rows</slot> </div> </div> </template> ``` ## Passing named content with `v-slot` and `#` The parent targets a named outlet with the `v-slot` directive and the slot name as its argument. `v-slot:toolbar` has the shorthand `#toolbar`: ```vue <DataTable :rows="orders"> <template #toolbar> <button @click="exportCsv">Export</button> </template> <tr v-for="o in orders" :key="o.id"><td>{{ o.id }}</td></tr> </DataTable> ``` Rules the compiler enforces: 1. `v-slot` may appear only on a component tag or a `<template>`; elsewhere the compiler reports `v-slot can only be used on components or <template> tags.` 2. Top-level nodes that are not `<template #...>` blocks are **implicit default slot** content. Writing `<template #default>` makes it explicit. 3. If a `<template #default>` exists, stray top-level nodes are reported as extraneous children and ignored. 4. Two fragments for the same slot name are a compile error (`Duplicate slot names found.`). ## Fallback content Whatever sits between an outlet's opening and closing tags is **fallback content**. It renders in place of the slot when the parent supplies nothing for it: | Parent passes | What the outlet renders | |---|---| | No fragment for the slot | The fallback | | A fragment that renders real nodes | The parent's content | | A fragment whose content is only comments, such as a false `v-if` | The fallback (Vue checks for valid content) | | `<template #empty v-if="false">` | The fallback, because the slot is not passed at all | The third row surprises people: Vue 3 does not just ask whether a slot function exists, it checks whether calling it produced anything other than comment placeholders. So a parent can supply an `#empty` fragment guarded by `v-if` and still get the child's default text when the condition is false. ## Named slots in practice - Keep the default slot for the component's main content and give every secondary region a name (`toolbar`, `empty`, `footer`). - Put sensible fallback content in outlets that should never look blank, such as an empty-state message. - Slot names are part of a component's public API: renaming one silently drops content from every caller, because an unmatched `<template #name>` fragment is simply never rendered. ## Syntax summary | Goal | Parent syntax | |---|---| | Default slot, implicit | Content directly inside the component tag | | Default slot, explicit | `<template #default>` | | Named slot | `<template #toolbar>` or `<template v-slot:toolbar>` | | Name chosen at runtime | `<template #[slotName]>` |
- In Vue 3, a parent renames `<template #empty>` to `<template #noData>` but the `DataTable` still has `<slot name="empty">`. What happens?The `noData` fragment matches no outlet and is never rendered, and there is no error. The `empty` outlet receives nothing, so its fallback text shows. Slot names are a contract: renaming one needs a coordinated change in the child and every caller.
- In Vue 3, where may the `v-slot` directive be written?Only on a `<template>` inside a component, or directly on the component tag itself when that component receives a single slot, usually the default one. On a plain element such as a `<div>`, the compiler reports that `v-slot` can only be used on components or `<template>` tags.
Named slots work like labelled mail slots on a door: the parent drops each envelope into the slot with the matching label, and a slot that receives nothing shows the note already taped behind it, which is the fallback.
saying these in an interview costs you the question
- An unnamed <slot> has no name, so it cannot be targeted explicitly.
- Fallback content renders only when the parent passes no fragment at all.
- v-slot:header can be put on any element, such as a div.
- Content for a slot name the child lacks throws an error at runtime.
- Named content must be passed with a slot attribute on the element.