The Difference Between Props, Slots and Scoped Slots in Vue.js
Let’s see what is the best way to pass data between components

When I started using Vue, I just passed data between components through the props, deepening this framework I found that I could achieve the same result with slots.
Let’s understand the differences and the reasons for using props instead of slots and vice versa.
PROPS
They are attributes that are exposed to accept data from the parent component.
Let’s create a component MyMessage
with props
<template>
<div class="message">
<h1>{{ msg }}</h1>
</div>
</template><script>
export default {
name: "MyMessage",
props: {
msg: String,
},
};
</script><style scoped>
.message {
color: red;
text-decoration: underline;
}
</style>
In this way, we are saying that the component accepts a value called msg
.
Now when we use this component we are able to pass a value through an attribute
<template>
<my-message msg="NotOnlyCSS is awesome!" />
</template><script>
import MyMessage from "./components/MyMessage.vue";export default {
name: "App",
components: {
MyMessage,
},
};
</script>
You can see the demo and play with props here on codesandbox.
Well I think it is now clear how the props work.
SLOTS
They allow you to compose component, also with HTML code.
Let’s create a component MyMessage
with slots
<template>
<div class="message">
<slot />
</div>
</template><script>
export default {
name: "MyMessage",
};
</script><style scoped>
.message {
color: red;
text-decoration: underline;
}
</style>
In this way, we are saying that the component accepts also a block of code through the slot
Now when we use this component, from the parent we can pass something like this
<template>
<my-message>
<h1>NotOnlyCSS is awesome!</h1>
<p>these are slots</p>
</my-message>
</template><script>
import MyMessage from "./components/MyMessage.vue";export default {
name: "App",
components: {
MyMessage,
},
};
</script>
You can see the demo and play with slots here on codesandbox.
NAMED SLOTS
There are times when it’s useful to have multiple slots, especially for more complex components.
Let’s create a component MyMessage
with named slots
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template><script>
export default {
name: "MyMessage",
};
</script><style scoped>
header {
color: red;
text-decoration: underline;
}
footer {
color: blue;
}
</style>
Now when we use this component, from the parent we can pass something like this
<template>
<my-message>
<template v-slot:header>
<h1>NotOnlyCSS is awesome!</h1>
</template> <template v-slot:default>
<p>A paragraph for the component.</p>
<p>And <b>another</b> one.</p>
</template> <template v-slot:footer>
<small>The footer of the component</small>
</template>
</my-message>
</template><script>
import MyMessage from "./components/MyMessage.vue";
export default {
name: "App",
components: {
MyMessage,
},
};
</script>
You can see the demo and play with named slots here on codesandbox.
Now it’s all clear right?
Working daily with Vue.js I discovered another type of slots, a little more complex but very useful too, they are called scoped slots, t’s go to better understand how they work.
SCOPED SLOTS
Sometimes, it’s useful to have access from the parent to data available in the child component, here scoped slots come in handy.
Let’s create a component MyMessage
with scoped slots
<template>
<div class="message">
<slot :firstName="firstName"></slot>
</div>
</template><script>
export default {
name: "MyMessage",
data() {
return {
firstName: "Luca",
};
},
};
</script><style scoped>
.message {
color: red;
text-decoration: underline;
}
</style>
To make a value available to the slot content provided by the parent, we can add a <slot>
element and bind it as an attribute.
Now we are able to access the value firstName also from the parent component like this
<template>
<my-message>
<template v-slot="slotProps">
<h1>Hey {{ slotProps.firstName }}, NotOnlyCSS is awesome!</h1>
</template>
</my-message>
</template><script>
import MyMessage from "./components/MyMessage.vue";
export default {
name: "App",
components: {
MyMessage,
},
};
</script>
You can see the demo and play with scoped slots here on codesandbox.
You may be thinking about when scoped slots are useful, a common case is when a component is used to render an array of items, and we want to be able to customize the way each item is rendered.
Conclusion
We have seen many ways of passing data between components, it depends on your needs whether to use props or slots.
With props, you can only pass values to the child component, so the parent wouldn’t be able to customize the child.
If you have a defined design and you just need to change some values, use props!
Slots give you more flexibility and allow you to customize the child component from the parent.
If you want to give the parent the freedom to customize components, use slots!