An introduction to Slots and Scoped Slots

David Del Prado
Jan 30, 2019 · 4 min read
introduction to Slots and Scoped Slots

As developers we always try to follow DRY (Don’t repeat yourself) principle to have a methodology to develop, modify, extend, normalise, test, etc.. our code and then use everywhere.

Vuejs provides us with cool functionalities that can be a great help for that. As seen previously in this blog, for business logic we talked about mixins in “Sharing logic between Vue components with mixins” and now it is time to see how to reuse and customise components.

In Geoblink we aim for consistency in our designs and at the same time we add a layer of customisation that enables us to reuse a component without having to modify it.

If you are not aware of the slots functionality a button component would be created like this:

Button with text as prop.

But when we are required to make any modification to a specific button, like adding and icon next to the text, we need to modify the component and add complexity with more and more props and html to be able to meet all design requirements.

Button with text and icon as props.

You can avoid all this complexity in the component by using slots. We will give you a short introduction to slots and how to use them.

Default slot

Following the previous example, we are going to remove the prop and replace it with a slot, which is a <slot></slot> tag. This slot tag can have a default content to render in case we don’t provide content in our component.

Button with slot to render any content inside.

Now we can add anything within the tags of our component and it will be rendered inside the button.

As we can see, we can meet design expectations without modifying the main component, that is being used all over our application, just because in one place it needs a specific template.

Named slots

Slots don’t stop at one per component, we can add as many slots as we want by adding the attribute ‘name’ to the slot tag.

We are going to create a modal with 3 different parts; header, body and footer, with default content but also have the possibility to change it by any other markup.

Modal with named slot for each section.

Have a look at the second modal, in this case we don’t want to show the same title and footer, so we can provide the custom content to the component, you only need an attribute slot="slotName" in the parent element of the content that we want to display.

<h5 slot="header" class="modal-title">Custom Modal</h5>
<button slot="footer" type="button" class="btn btn-primary">

These two tags will be rendered in its corresponding slot instead of the default header and footer.

With the default slot and named slots we can already customise in a great way the components and there is one step further to have even more control of how and what we can change to our needs.

Scoped slots

Scoped-slots were introduced in VueJS 2.1.0, a functionality little known but quite useful. With a scoped slot we can send data from the component owning the slot to the component being rendered inside the slot, which gives us great power to decouple logic from the component and give that responsibility to the parent component.

One of the use cases to get the most out of a scoped slot is when iterating over collections. To better explain this case we are going to create a table component that has a prop called ‘ tableData’ .

Table with named slots and scoped slots for customisation.

The only properties required in the model are an array of ‘headers’ and ‘rows’, but apart from that, the items of each array can be as we want.

To use the default behaviour of the table, we can set on each item a property called ‘label’ and we won’t need anything more (Default Table example).

But to be realistic, we seldom would require such a simple table. Our headers or rows are expected to have more functionalities like adding more markup, custom actions, colors, etc. Now is when the scoped slots come in handy.

To create the scope we just need to add a prop in the slot tag with the data needed in the parent <slot :header="header" /> and then in the parent component receive it with slot-scope="{ header }" (see ES6 destructuring) or slot-scope="data" (without ES6).

The difference is how we use it in the template:

<th slot="header" slot-scope="{ header }">
{{ header.label }}


<th slot="header" slot-scope="data">
{{ data.header.label }}

Now we have the potential to use any shape of model as item in the ‘headers’ array and leave the responsibility to the parent component to implement the markup and logic needed.

I hope this introduction is of help and encourages you to bring to the next level your components 😊!

Tech&Data blog from the team powering the Geoblink systems. We are the engineers, developers, data scientists, mathematicians and physicists trying to build the best Location Intelligence tool out there.

David Del Prado

Written by

Geoblink Tech blog

More From Medium

More from Geoblink Tech blog

More on JavaScript from Geoblink Tech blog

More on JavaScript from Geoblink Tech blog

Open sourcing our Design System

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade