React

Named slots in Vue 3: composing components without extra props

Named slots let the parent fill precise regions of a child: the component owns the layout and the page owns the content of each region.

Key points

  • The unnamed slot is the default one and receives everything the parent writes between the tags.
  • Markup inside <slot> is the fallback and shows only when the parent passes nothing.
  • A scoped slot exposes child data to the parent, which decides how to render it.

A named slot is a named hole: the child declares <slot name="header"> and the parent fills it with <template #header>. The component keeps no props and no content logic.

The component that owns the layout


defineProps();



  
    
      
        {{ title }}
      
    

    

    
      
    
  

Content inside <slot> is the fallback: it shows only when the parent passes nothing. The card therefore works on its own and accepts customisation when needed.

Scoped slots: data from child to parent


const rows = [
  { id: 1, name: "Ada", role: "admin" },
  { id: 2, name: "Linus", role: "editor" },
];



  
    
      
        {{ row.name }}
      
    
  

The child decides which data to expose, the parent how to show it. That is the difference from a prop: here the structure stays in the child and the rendering in the parent.

Slots or props?

CaseWinnerWhy
Plain text the child already knowsPropShorter to read in the template
Markup with links and iconsSlotThe parent keeps its own components
One list rendered differently per pageScoped slotData stays in the child, rendering in the parent
A form whose fields the parent controlsScoped slotThe child holds state, the parent holds the controls

Common mistakes

  • Renaming a slot without updating the parent: the content can vanish with no visible error.
  • Putting #header and v-slot on the same tag: the compiler reports a syntax error.
  • Skipping the fallback: with an empty parent you get a hole in the layout.
  • Using a slot inside a v-for without :key on the node outside the list.

The limitation to plan for

Slots have no type contract on their content: TypeScript checks the data of a scoped slot, not what the parent writes inside. A wrong name produces a silent hole, not a compile error.

Where to go next

In the catalogue: shadcn-vue, vue-bits and Ant Design Vue; ready-made layouts are in /blocks. The guides: Composition API and props that do not update. The comparison: Vue vs React, where the same job goes through children.

Frequently asked questions

Can a named slot have a default?

Yes: the content written inside the slot tag in the child is the fallback, and it shows only when the parent passes nothing.

How is this different from props?

Props carry data, slots carry markup. With rich markup, slots keep the parent components out of the child.

What are scoped slots?

Slots that expose child data to the parent through attributes on the slot tag. The parent reads them with v-slot and decides how to render.

Can I have more than one default slot?

No, there is only one default slot. Multiple blocks in the default are concatenated, so distinct regions need distinct names.

Do slots break reactivity?

No. Slot content stays in the parent context and keeps its own reactive dependencies.