vuejs-que-son-los-slots

Qué son y cómo usar Slots en Vue.js

  • 3 min

En Vue.js, un slots son una mecanismo que permite de inyectar un fragmento de HTML en un componente, desde otro componente padre.

Es decir, es como si el componente hijo tuviera un “hueco”, donde deja que otros le pasen contenido HTML, para que lo muestre dentro suyo.

De esta forma podemos reusar nuestro componente, que actúa como un “marco de imagen”, para un contenido que puede ser variable.

Por ejemplo, imagina que tienes un componente que marca una tarjeta muy elaborada. Otro componente puede pasarle el contenido que debe mostrar en el interior de la tarjeta.

Los Slots son una alternativa a las Props, cuando no solo tengamos que cambiar ciertos valores, si no todo el contenido del componente.

¿Qué son los slots?

El slot por defecto son los más básicos y comunes. Nos permite insertar un único contenido en un solo lugar dentro del componente hijo

En el componente hijo, la etiqueta <slot> actúa como un “marcador de posición” que será sustituido por el contenido insertado.

<template>
  <div class="card">
    <slot></slot> <!-- Slot por defecto -->
  </div>
</template>

<style>
.card {
  border: 1px solid #ccc;
  padding: 20px;
  border-radius: 8px;
}
</style>
<template>
  <CardComponent>
    <p>Este es el contenido de la tarjeta.</p>
  </CardComponent>
</template>

<script setup>
import CardComponent from './CardComponent.vue';
</script>

En este ejemplo:

  • El componente hijo (CardComponent) define un slot por defecto.
  • El componente padre (ParentComponent) inserta contenido dentro del slot.

Slots con nombre

Los slots con nombre son un mecanismo que nos permite que un componente ofrezca múltiples slots. Para ello, vamos a ponerle a cada slot un nombre único (para poderlo referenciar).

<template>
  <div class="layout">
    <header>
      <slot name="header"></slot> <!-- Slot con nombre "header" -->
    </header>
    <main>
      <slot></slot> <!-- Slot por defecto -->
    </main>
    <footer>
      <slot name="footer"></slot> <!-- Slot con nombre "footer" -->
    </footer>
  </div>
</template>

<style>
.layout {
  border: 1px solid #ccc;
  padding: 20px;
  border-radius: 8px;
}
</style>
<template>
  <LayoutComponent>
    <template v-slot:header>
      <h1>Encabezado Personalizado</h1>
    </template>
    <p>Este es el contenido principal.</p>
    <template v-slot:footer>
      <p>Pie de página Personalizado</p>
    </template>
  </LayoutComponent>
</template>

<script setup>
import LayoutComponent from './LayoutComponent.vue';
</script>

En este ejemplo:

  • El componente hijo (LayoutComponent) define tres slots: header, footer y un slot por defecto.
  • El componente padre (ParentComponent) inserta contenido en cada slot usando v-slot.

Scoped Slots

Los slots con scope permiten pasar datos del componente hijo al componente padre. Esto es útil cuando el fragmento HTML que estamos insertando a su vez necesita acceder al contenido del componente que lo va a insertar en el slot.

<template>
  <ul>
    <li v-for="(item, index) in items" :key="index">
      <slot :elemento="item" :indice="index"></slot>
    </li>
  </ul>
</template>

<script setup>
import { ref } from 'vue'

const items = ref(['Manzana', 'Banana', 'Cereza', 'Durazno'])
</script>
<template>
  <Lista>
    <template v-slot:default="{ elemento, indice }">
      <strong>{{ indice + 1 }}:</strong> {{ elemento.toUpperCase() }}
    </template>
  </Lista>
</template>

<script setup>
import ChildComponent from './ChildComponent.vue'
</script>

En este ejemplo:

  • El componente hijo (ChildComponent.vue) crea una lista de elementos y expone cada uno mediante el slot usando :elemento y :indice.
  • El componente padre (App.vue) usa v-slot para recibir esos datos y personalizar el contenido de cada elemento.