En el artículo anterior vimos como crear un Shadow DOM para crear DOM particulares o locales en elementos HTML específicos. Si recordamos, vimos que el DOM que teníamos en el elemento (Light DOM), era oscurecido por el Shadow DOM, y en el navegador pasaban a ser renderizados sólo los elementos del Shadow DOM.
¿Qué son los slots?
Los slots o ranuras son una característica del DOM mediante la cuál podemos insertar fragmentos del Light DOM en nuestro Shadow DOM. Se puede ver como «pequeños huecos» en el Shadow DOM por donde se pueden ver partes de luz que realmente están en el Light DOM.
Veamos un ejemplo sencillo:
const container = document.querySelector('.container');
container.attachShadow({ mode: "open" });
container.shadowRoot.innerHTML = `<div><h1>Shadow DOM</h1><slot></slot></div>`;
<div class="container">
<p>El contenido original del DOM.</p>
</div>
Como podemos ver, en este caso, el elemento <slot>
deja pasar todo el contenido original de la etiqueta .container
al Shadow DOM.
Slots múltiples
Para casos básicos, nos basta con utilizar un sólo <slot>
que obtiene el contenido íntegro del Light DOM. Sin embargo, podemos utilizar múltiples <slot>
para insertar fragmentos específicos:
const container = document.querySelector('.container');
container.attachShadow({ mode: "open" });
container.shadowRoot.innerHTML = `<div>
<slot name="title">Título sin definir</slot>
<slot name="description">Descripción sin definir</slot>
</div>`;
// Tras 4 seg, eliminamos el contenido del LightDOM
setTimeout(() => container.innerHTML = '', 4000);
<div class="container">
<h1 slot="title">Este es el título</h1>
<p slot="description">Esta es la descripción</p>
</div>
Observa que en este caso, hemos utilizado las etiquetas <slot>
añadiéndole un atributo name
para darles un nombre. Luego, en el Light DOM, hemos definido la etiqueta que nos interesa, añadiéndole un atributo slot
que coincida con el name
del slot del Shadow DOM.
Además, fíjate en el setTimeout()
que hemos definido para eliminar el contenido del Light DOM a los 4 segundos. De esta forma se ve claramente, que si no hay una etiqueta con atributo slot
, el Shadow DOM utiliza el contenido del slot como contenido a utilizar por defecto.
Si quieres aprender más sobre los slots, puedes consultar el artículo Slots en WebComponents.
Acceso a los slots desde Javascript
Si queremos hacer alguna acción concreta, mediante Javascript podemos acceder a los slots o a los elementos insertados en los slots, a través de varias propiedades o métodos:
Propiedad | Descripción |
---|---|
Slot del Shadow DOM | |
.name | Devuelve el nombre del slot (simplemente, su atributo HTML). |
.assignedElements() | Devuelve un array con los elementos asignados al slot. |
.assignedNodes() | Devuelve un array con los nodos (elementos y textos) asignados al slot. |
Elemento insertado en el slot | |
.slot | Devuelve el nombre del slot referenciado (simplemente, su atributo HTML). |
.assignedSlot | Devuelve el slot donde se ha asignado este elemento. |
Como puedes ver, los <slot>
pueden tener varios elementos asignados, simplemente referenciandolo por el nombre. La diferencia entre .assignedElements()
y .assignedNodes()
es que el primero se basa en
Dando estilo a los slots
El contenido que está dentro de un <slot>
no se puede estilar desde el Shadow DOM, ya que pertenece al DOM global. Sólo podemos estilarlo desde el DOM global, o desde el Shadow DOM utilizando el pseudoelemento ::slotted()
para dar estilo a los elementos insertados en el slot:
const container = document.querySelector('.container');
container.attachShadow({ mode: "open" });
container.shadowRoot.innerHTML = `<div>
<style>
h1 { color: white; background: indigo; }
::slotted(p) { background: steelblue; }
</style>
<h1>Shadow DOM</h1>
<slot></slot>
</div>`;
<style>
h1 { color: red }
p { color: white; padding: 10px; }
</style>
<div class="container">
<p>El contenido original del DOM.</p>
</div>
Observa que en el caso del <h1>
el CSS global no afecta al <h1>
del Shadow DOM (está encapsulado). Sin embargo, las ranuras slot si que afectan ambos. El CSS global afecta a la etiqueta <p>
porque está en el DOM global, pero también podemos afectarla mediante ::slotted()
en el Shadow DOM.
Mediante
::slotted()
sólo se pueden estilar los elementos de primer nivel. Si quisieramos darle estilo a los elementos hijos anidados, no podríamos hacerlo. En esos casos, mi recomendación es investigar como funciona CSS Parts y su pseudoelemento::part()
.
Los slots en el SEO
Los <slot>
son un mecanismo muy interesante en el SEO (Optimización en motores de búsqueda), sobre todo cuando utilizamos Javascript para crear el DOM.
Utilizando <slot>
, podemos añadir todo el contenido sensible a ser indexado en el Light DOM, mientras que en el Shadow DOM con Javascript, añadimos sólo la parte que no sea interesante de cara a buscadores.
Tradicionalmente, en el contexto de SEO, Google y otros motores de búsqueda pueden no indexar completamente tu sitio web si está construido con Javascript de cliente. Más información en este excelente post de Vercel: How Google handles Javascript throughout the indexing process.