Vue3 Slot

In Vue components can set a slot tag in the template, which is used to pass some content when using this component to replace the slot.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<FancyButton>
  Click me! <!-- slot content -->
</FancyButton>

<button class="fancy-btn">
  <slot></slot> <!-- slot outlet -->
</button>

// final output
<button class="fancy-btn">Click me!</button>

The content passed to the slot can be text or an HTML element.

Scope

The rendering scope of the slot is limited to the parent component. When a variable is passed in, this variable can only access the parent component and cannot access the variables of the child component.

Expressions in the parent template only have access to the parent scope; expressions in the child template only have access to the child scope.

In some cases, the content of the slot needs to be set according to the variables of the component itself. In this case, attributes can be passed to the component like passing props to the component. At this time, the content of the slot can be obtained according to the variables of the child component.

1
2
3
4
5
6
7
8
<!-- <MyComponent> template -->
<div>
  <slot :text="greetingMessage" :count="1"></slot>
</div>

<MyComponent v-slot="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>

Essentially, it can be regarded as passing a function down, which is called by the component.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
MyComponent({
  // passing the default slot, but as a function
  default: (slotProps) => {
    return `${slotProps.text} ${slotProps.count}`
  }
})

function MyComponent(slots) {
  const greetingMessage = 'hello'
  return `<div>${
    // call the slot function with props!
    slots.default({ text: greetingMessage, count: 1 })
  }</div>`
}

Fallback Content

Components can set default values for slots.

1
2
3
4
5
<button type="submit">
  <slot>
    Submit <!-- fallback content -->
  </slot>
</button>

Named Slot

If there are multiple slots in a component, they can be distinguished by the name attribute. When using, you can specify which slot is passed through the attribute v-slot:slotName or the abbreviation #slotName, and the default is default when not filled.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

<BaseLayout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <template #default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</BaseLayout>

The default top-level elements are all passed to the default slot.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<BaseLayout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <!-- implicit default slot -->
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</BaseLayout>

Dynamic Slot Name

You can use dynamic variables or expressions as slot names through square brackets.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

  <!-- with shorthand -->
  <template #[dynamicSlotName]>
    ...
  </template>
</base-layout>