Using Scoped Slots in Vue.js

Alex Jover Morales

Alex Jover Morales

Sep 15, 2019
3 min read
Share on Twitter or LinkedIn

Multiple times I get to know companies that want to improve their productivity when coding in Vue.js.

That's a too open question, but at least some part can be achieved that by identifying what functionality they build pretty often in their apps, and then having a toolkit of reusable components that allow you to put that common logic in there, while being flexible enough to adapt to other apps.

Vue.js has slots in order to make components have a redefinable structure, but by themselves they're pretty limited. Sometimes you need some data or state in order to define how a component should render.

If you don't know slots, I suggest you learn them first on the Vue.js docs.

Scoped slots is an advanced feature in Vue.js that allows you to do that. They're like normal slots, but they can receive properties as well.

Let's build a Clock.vue component in order to illustrate that. Basically it must be a time counter:

<template>
  <div class="clock">
    <slot :time="time">
      <p>Default slot</p>
      <p>Time: {{ time.toLocaleTimeString() }}</p>
    </slot>
  </div>
</template>

<script>
  export default {
    data: () => ({
      time: new Date()
    }),
    created() {
      setInterval(() => {
        this.time = new Date(this.time.getTime() + 1000);
      }, 1000);
    }
  };
</script>

You might have noticed the <slot :time="time"> line, that's the slot receiving the time property. That's the way this Clock.vue component can send the time data to the component that uses it, while encapsulating the timer logic itself.

You also might have realised that this component already renders the time by itself, as it has some default content within the slot.

But what if we want to redefine what it renders, while holding the timer logic in it?

Well, since we're passing the time property to the slot, we can do that simply by using the v-slot directive on the root element of the Clock slot. So, wherever you want to render the Clock component, you'll write something like:

<template>
  <Clock>
    <template v-slot="{ time }">
      <p><b>Slot override!</b></p>
      <p>Date: {{ time.toLocaleDateString() }}</p>
      <p>Time: {{ time.toLocaleTimeString() }}</p>
    </template>
  </Clock>
</template>

v-slot receives all the props passed from within the Clock component. Since that's JavaScript object, we can use the Object Spread Operator to already grab the time prop as { time }.

Do you see the power of Scoped Slots? You can do more powerful stuff, like render-less components, that you'll see in a future tip 😜.

If you want to run the code yourself, you can find it in this CodeSandbox!

Don't miss out anything about Vue, your favourite framework.

Subscribe to receive all the articles we publish in a concise format, perfect for busy devs.

Related Articles

The new Provide and Inject in Vue 3

Getting stuck into the prop drilling? Learn how provide/inject can make your components more flexible and independent in this short tutorial.

Anthony Konstantinidis

Anthony Konstantinidis

Jul 18, 2022

Data Provider component in Vue.js

Use scoped slots to create a data provider in Vue.js

Alex Jover Morales

Alex Jover Morales

Sep 24, 2019

Create an ImageSelect component on top of vue-multiselect

Build an ImageSelect Vue.js component using the popular vue-multiselect package following the Adaptive Components pattern.

Alex Jover Morales

Alex Jover Morales

Feb 24, 2019

Sponsors

VueDose is proudly supported by its sponsors. If you enjoy it, consider supporting it to ensure the project maintainability.

Silver
Learning Partner