Slots com escopo no Vue.js
Em determinados cenários, é necessário acessar dados internos de um componente filho no conteúdo que o componente pai envia para ele. Um caso comum ocorre quando se tenta acessar dados definidos no filho diretamente dentro do corpo do componente pai. Considere o seguinte código:
Componente pai:
<div id="app">
<user>
<h3>Dados do usuário</h3>
<p>Nome: {{ user.name }}</p>
<p>Idade: {{ user.age }}</p>
</user>
</div>
Componente filho:
const app = Vue.createApp({});
app.component('user', {
data() {
return { user: { name: 'Tom', age: 36 } };
},
template: `<div><slot></slot></div>`
});
app.mount('#app');
Esse código não funciona porque o componente pai não tem acesso ao objeto user, que está definido apenas dentro do componente user
{{ user.name }}
{{ user.age }}
Para resolver esse tipo de situação, pode-se recorrer aos slots com escopo (scoped slots). Esse recurso permite que o componente filho envie dados ao conteúdo que o pai define dentro do slot. Os dados disponibilizados pelo filho ficam acessíveis apenas dentro desse escopo.
No componente pai, o slot é declarado dentro de um <template>
v-slot
A seguir, um exemplo funcional usando scoped slots:
<!DOCTYPE html>
<html>
<head>
<title>Slots Vue 3</title>
<meta charset="utf-8" />
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<user>
<template v-slot:default="props">
<h3>Dados do usuário</h3>
<p>Nome: {{ props.userinfo.name }}</p>
<p>Idade: {{ props.userinfo.age }}</p>
</template>
</user>
</div>
<script>
const app = Vue.createApp({});
app.component('user', {
data() {
return { user: { name: 'Tom', age: 36 } };
},
template: `
<div>
<slot v-bind:userinfo="user"></slot>
</div>
`
});
app.mount('#app');
</script>
</body>
</html>
Neste exemplo, o componente user
user
v-bind:userinfo="user"
v-slot:default="props"
props.userinfo
Como o slot não possui um nome explícito, o Vue o trata como default
v-slot:default
props
Esse padrão também pode ser aplicado a listas, permitindo que o componente pai controle a estrutura visual de cada item:
<!DOCTYPE html>
<html>
<head>
<title>Slots Vue 3</title>
<meta charset="utf-8" />
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<userslist>
<template v-slot:userdetails="props">
<div>
<p>Nome: {{ props.userinfo.name }}</p>
<p>Idade: {{ props.userinfo.age }}</p>
</div>
</template>
</userslist>
</div>
<script>
const app = Vue.createApp({});
app.component('userslist', {
data() {
return {
users: [
{ name: 'Tom', age: 36 },
{ name: 'Sam', age: 39 },
{ name: 'Bob', age: 25 }
]
};
},
template: `
<ul>
<li v-for="user in users">
<slot name="userdetails" v-bind:userinfo="user"></slot>
</li>
</ul>
`
});
app.mount('#app');
</script>
</body>
</html>
O componente userslist
users
userdetails
v-bind:userinfo="user"
O componente pai define o conteúdo do slot userdetails
v-slot:userdetails="props"
props.userinfo
Esse padrão permite que o pai controle completamente a estrutura e a apresentação dos dados, enquanto o componente filho se responsabiliza apenas pela lógica de dados e repetição.

Resumo
Scoped slots permitem que um componente filho envie dados ao conteúdo definido no slot pelo componente pai.
O slot é declarado no pai com
.<template v-slot:nome="variável">
Os dados são enviados pelo filho com
dentro do slot.v-bind
Quando o slot não possui nome, o Vue o trata como
, e o pai deve usardefault
.v-slot:default
O pai pode acessar os dados enviados por meio do identificador declarado no
.v-slot
Esse recurso oferece flexibilidade para controlar a estrutura visual no pai enquanto o filho gerencia os dados.