Como crear custom elements (Shadow DOM)

blog tutorial webcomponents

Una característica muy interesante que forma parte de HTML5 y que últimamente ha estado recibiendo mucha atención son los custom elements (elementos personalizados).

¿Qué es un custom element?

Los custom elements son elementos HTML que nosotros podemos crear y que vienen con su propia API de JavaScript. Esto daría solución a la famosa enfermedad de Divinitis

Aquí un caso real de Divinitis:

HTML
<div class="contenedor">  
    <div class="header">
        <h1 class="titulo">Título</h1>
    </div>
    <div class="cuerpo">
        <div class="superior">
            <p>Texto ...</p>
        </div>
        <div class="inferior">
            <p>Texto ...</p>
        </div>
    </div>
    <div class="footer">
        <p>Footer...</p>
    </div>
</div>

Divinitis en caso terminal:

Los custom elements también son muy útiles en la reutilización de código en una aplicación.

Creación de un custom element

Como ejemplo para este artículo vamos a crear un botón llamado boton-x el cual va a tener dos parámetros personalizados:

  • nombre-epico
  • url-epica

Empezaremos definiendo nuestro custom element con nuestros parámetros:

HTML
<boton-x nombre-epico="Fili Santillán" url-epica="https://filisantillan.com/"></boton-x>

Importante: El nombre de un custom element siembre debe de contener un guión (-) para que el navegador pueda diferenciar entre elementos HTML estándar y personalizados.

Ahora vamos a crear una variable miBoton que contenga un objeto JavaScript pasando HTMLElement.prototype:

Javascript
var miBoton = Object.create(HTMLElement.prototype);

Lo siguiente es definir una función para el createdCallback:

Javascript
miBoton.createdCallback = function() {  
    ...
};

Existen una serie de callbacks que pueden escuchar cuando creamos y gestionamos nuestros elementos personalizados.

  • createCallback: Entra en acción cuando se crea un custom element.

  • attachedCallback: Entra en acción cuando se inserta un custom element en el DOM.

  • detachedCallback: Entra en acción cuando se elimina un custom element del DOM.

  • attributeChangedCallback (nombreDelAtributo, valorAntiguo, nuevoValor): Entra en acción cuando el atributo de un custom element cambia.

Dentro de nuestra función vamos a usar createShadowRoot, luego creamos un elemento <a> estableciendo dentro un nombre y el parámetro <href>:

Javascript
miBoton.createdCallback = function() {

    var shadow = this.createShadowRoot(); // Creamos el Shadow Root

    var link = document.createElement("a"); // Creamos nuestro elemento "<a>"
    link.innerText = this.getAttribute("nombre-epico"); // Insertamos el valor que hay en "nombre-epico" como nodo en "<a>"
    link.href = this.getAttribute("url-epica"); // Agregamos el atributo href con el valor de "url-epica"
    link.className = "link-x"; // Agregamos la clase link-x

    shadow.appendChild(link); // Agregamos link al Shadow Root
};

createShadowRoot crea una instancia del shadow DOM.

Si quieres saber más sobre createShadowRoot y el shadow DOM te recomiendo ver el siguiente enlace de Mozilla Developer Network.

Ahora tenemos que registrar el custom element usando document.registerElement () con dos atributos:

Javascript
var botonX = document.registerElement("boton-x", {  
    prototype: miBoton
});
  • boton-x representa el nombre de nuestro elemento.

  • miBoton representa el valor de prototype (prototipo).

Nuestro código JavaScript se debería ver de la siguiente manera:

Javascript - Completo
var miBoton = Object.create(HTMLElement.prototype);

miBoton.createdCallback = function() {

    var shadow = this.createShadowRoot();

    var link = document.createElement("a");
    link.innerText = this.getAttribute("nombre-epico");
    link.href = this.getAttribute("url-epica");
    link.className = "link-x"

    shadow.appendChild(link);
};

var botonX = document.registerElement("boton-x", {  
    prototype: miBoton
});

Como extra vamos a agregar un poco de estilos:

CSS
boton-x {  
  padding: 10px 20px;
  display: inline-block;
  background: #4299D4;
  border-radius: 5px;
  margin: 20px;
  box-shadow: 4px 4px 0 #1E252A;
  border: 1px solid #1E252A;
}

boton-x::shadow .link-x { /* .link-x es la clase que agregamos con JS*/  
  color: #1E252A;
  text-decoration: none;
  font-family: 'Arial';
  font-size: 23px;
  letter-spacing: 4px;
}

Advertencia: Es necesario agregar ::shadow para que se apliquen los estilos dentro de nuestros custom elements.

El resultado del custom element que acabamos de hacer es el siguiente:

¡Listo!, puede que esto te parezca algo abrumador (muchos conceptos en un solo artículo), pero la verdad es que una vez que lo entiendes es bastante fácil de usar, ten paciencia, practica y ve entendiendo poco a poco este concepto.

Te dejo otro ejemplo de custom elements un poco más complejo:

See the Pen Custom - elements by Fili Santillán 👾 (@FiliMX) on CodePen.