Essentials

When/Why to Use Vue Scoped Slots

Matt Maribojoc

Matt Maribojoc · 4 min read

Mar 29, 2021

Vue slots are a fantastic way to inject content from a parent component into a child component.

Here’s the most basic example, whatever we put inside <slot> will be the fallback content if we don’t give any slot content from the parent.

ChildComponent.vue

markup
<template>
  <div>
     <slot> Fallback Content </slot>
  </div>
</template>

And then in our parent component…

ParentComponent.vue

markup
<template>
   <child-component>
      Override fallback content
   </child-component>
</template>

When compiled, our DOM will look something like this.

Injecting our slot content!

markup
<div> Override fallback content </div>

We can also include any data from our parent scope inside our slot content. So if our component had a data field called name, we can easily add it like this.

We can inject parent component data

vue
<template>
  <child-component> {{ text }} </child-component>
</template>

<script>
  export default {
    data() {
      return {
        text: "hello world",
      };
    },
  };
</script>
 

This is just a brief overview, for a more in-depth guide on slot, check out Using Component Slots in VueJS — An Overview.

Why do we need scoped slots

Let’s take a look at another example, say we have an ArticleHeader component that contains some article info in its component data.

ArticleHeader.vue

vue
<template>
  <div>
    <slot v-bind:info="info"> {{ info.title }} </slot>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        info: {
          title: "title",
          description: "description",
        },
      };
    },
  };
</script>
 

If we take a closer look at the slot, we’ll see that the fallback content renders the info.title of our article.

Without changing the default fallback content, we can easily implement this component like this.

ParentComponent.vue

vue
<template>
  <div>
    <article-header />
  </div>
</template>
 

And if we look in our browser, our app will be showing the title.

While we could easily change the content of our slot by adding a template expression into our slot, what happens if we want to render the info.description from our child component.

It may seem like all you have to do is add it into our slot..

Doesn't work!

markup
<template>
  <div>
    <article-header>
        {{ info.description }}
    </article-header>
  </div>
</template>

But if we run this, we get an error: TypeError: Cannot read property ‘description’ of undefined

And that’s because our parent component has no clue what this info object is.

So how do we solve this?

Introducing scoped slots!

Simply put, scoped slots allow our slot content in our parent component to have access to data that’s only found in the child component. For example, we can use a scoped slot to give our parent component access to info.

There are two steps we need to do this:

  • Make info available to the slot content using v-bind

  • Use v-slot in our parent scope to access the slot props.

First, to make info available to the parent, we can bind our info object as an attribute on our slot. These bounded attributes are called slot props.

The code for that is as easy as this.

ArticleHeader.vue - Binding Slot Props

markup
<template>
  <div>
    <slot v-bind:info="info"> {{ info.title }} </slot>
  </div>
</template>

Then, in our parent component, we can access all of our slot props using <template> together with the v-slot directive.

ParentComponent.vue - Accessing Slot Props

markup
<template>
  <div>
    <child-component>
      <template v-slot="article">
        
      </template>
    </child-component>
  </div>
</template>

Now, all of our slot props, which for our example, is only info will be available as a property on our article object, and we can easily change our slot to show our description.

ParentComponent.vue - using slot props

markup
<template>
  <div>
    <child-component>
      <template v-slot="article">
        {{ article.info.description }}
      </template>
    </child-component>
  </div>
</template>

Our final product will then look like this.

Awesome!

Conclusion

While Vue scoped slots are a pretty simple concept – give your slot content access to your child component data – it’s super powerful in designing amazing components. By keeping data in one spot and binding it to other places, managing different states becomes much clearer.

I hope this article helped you get a basic idea of how Vue scoped slots work. If you have any questions, leave them in the replies down below!


Join the LearnVue Community

Every week we send out exclusive content to thousands of developers on our mailing list. 100% Free.

Latest Posts

Top Tools

Making a Markdown-Based Blog with Vue and Gridsome

Use Vue with Gridsome is one of the easiest ways to create static websites from just Markdown files.

Matt Maribojoc · 12 min Read More
Top Tools

5 VueUse Library Functions That Can Speed Up Development

VueUse is an open-source project that provides Vue developers with a huge collection of essential Composition API utility functions for both Vue 2 and Vue 3.

Matt Maribojoc · 12 min Read More
Dev Tips

Lazy Load Components in Vue with defineAsyncComponent

Using Vue 3’s defineAsyncComponent feature lets us lazy load components - meaning they’re only loaded when they’re needed.

Matt Maribojoc · 7 min Read More
Essentials

The Beginner’s Guide to Vue Template Refs - with Vue 3 Updates

Vue Template Refs give our Javascript code a reference to easily access the template.

Matt Maribojoc · 5 min Read More