Elementos personalizados

facebook-svg gplus-svg twitter-svg

¿Qué es el shadow DOM?

DOM es el acrónimo de Document Object Model que podemos traducir como 'Modelo de Objetos del Documento' o 'Modelo en Objetos para la Representación de Documentos'.

El DOM es una interfaz que proporciona un conjunto de objetos para representar documentos HTML, XHTML y XML y las relaciones entre estos objetos ( relaciones de tipo padre hijo hermanos ). También proporciona un conjunto de métodos para acceder a estos elementos y manipularlos. Debido a las relaciones de tipo padre hijo hermanos entre elementos el DOM tiene la apariencia de un árbol ( DOM tree ).

El Shadow DOM es una estructura DOM oculta ( shadow == sombra en ingles ). Un ejemplo sería un elemento audio que tiene todos aquellos controladores, una serie de botones para reproducir, parar, cambiar el volumen etc. . .

Todos estos controladores son invisibles en el DOM y se encuentran encapsulados en el Shadow tree

Terminología útil

- El Shadow Host: Es el elemento portador, el elemento audio del ejemplo anterior.
- El Shadow Tree: la estructura o el árbol ( tree == árbol ) del Shadow DOM ( el DOM oculto ).
- El Shadow Boundary:  marca los límites del Shadow DOM, donde este acaba y donde el DOM empieza.
- El Shadow Root:  es el elemento raíz ( root == raíz ) del Shadow Tree.

See the Pen shadow tree by Gabi (@enxaneta) on CodePen.

El Shadow Root puede ser abierto ( open ) o cerrado ( closed ). Es posible manipular los nodos del Shadow DOM, exactamente de la misma manera  como manipulamos los nodos del DOM, con la condición que sea creado utilizando el método attachShadow() y que sea abierto ( open ).

let shadow = elemento.attachShadow({mode: 'open'});

Podemos:
- agregar elementos al shadow DOM utilizando el método appendChild()
- establecer el valor de los atributos utilizando el método setAttribute()
- dar estilo a los nodos con CSS
- incluso es posible añadir un elemento <style> dentro del shadow DOM. En este caso el CSS queda encapsulado en el shadow DOM y no afecta a los elementos situados fuera de la "cápsula".

Crear elementos HTML personalizados

El siguiente ejemplo es una adaptación de un ejemplo de MDN: Using shadow DOM

En JavaScript primero definimos una nueva clase de objetos llamada PopUpInfo


class PopUpInfo extends HTMLElement {
    constructor() {
      // cuando se trata de una clase que extiende otra clase tenemos que utilizar la palabra clave super para invocar la clase padre
      super();
  . . . . . . . 
    }
  }

Cómo crear clases de objetos en ES6

En el constructor de la clase creamos un elemento raíz  ( shadow root ):


//creando el shadow root
var shadow = this.attachShadow({ mode: "open" });

En este caso utilizamos mode: "open" lo que quiere decir que es posible acceder y  manipular el shadow DOM con JavaScript. A continuación creamos la estructura del shadow DOM:


// 1. crea un envoltorio
var wrapper = document.createElement("span");
wrapper.setAttribute("class", "wrapper");
// 2. crea un ícono
var icon = document.createElement("span");
icon.setAttribute("class", "icon");
icon.setAttribute("tabindex", 0);
// 3. crea un elemento span donde poner el texto informativo
var info = document.createElement("span");
info.setAttribute("class", "info");

El elemento <span class="info"> toma como textContent el valor del atributo text del elemento <popup-info>.


var text = this.getAttribute("text");
info.textContent = text;

El ícono creado anteriormente tiene dentro un elemento <img> y utiliza el valor del atributo img del elemento <popup-info> como src para la imagen del shadow DOM.


// Añade la imágen para el ícono
var imgUrl;
if (this.hasAttribute("img")) {
imgUrl = this.getAttribute("img");
} else {
// utiliza una imagen por defecto
imgUrl = "cat.svg#blackcat";
}
var img = document.createElement("img");
img.src = imgUrl;
icon.appendChild(img);

Crea un nuevo elemento <style> donde poner las reglas CSS para el shadow DOM


//Los estilos para el shadow DOM
var style = document.createElement("style");

style.textContent = `

.wrapper {   position: relative; } .info {   font-size: 0.8rem;   width: 200px;   display: inline-block;   border: 1px solid black;   padding: 10px;   background: white;   border-radius: 10px;   opacity: 0;   transition: 0.6s all;   position: absolute;   bottom: 20px;   left: 10px;   z-index: 3; } img {   width: 1.2rem; } .icon:hover + .info, .icon:focus + .info {   opacity: 1; }`; //Agrega los estilos al shadow DOM shadow.appendChild(style); //Agrega el wrapper al shadow DOM shadow.appendChild(wrapper); //Agrega el ícono al wrapper wrapper.appendChild(icon); //Agrega el span.info al wrapper wrapper.appendChild(info);

}// acaba el constructor }// acaba la clase de objetos PopUpInfo

Finalmente define un nuevo elemento HTML personalizado: <popup-info>

customElements.define("popup-info", PopUpInfo);

Una vez definida la nueva clase de elementos HTML personalizados, podemos utilizar el <popup-info> en el HTML


Pasa con el ratón por encima del gato: para ver lo que pasa.

Vea este ejemplo en codepen:

See the Pen shadow root by Gabi (@enxaneta) on CodePen.

Artículo relacionado

  • - Elementos personalizados