Shadow DOM en TypeScript

Shadow DOM en TypeScript

Este artículo explica Shadow DOM en TypeScript.

Explicaremos cuidadosamente todo, desde los conceptos básicos de Shadow DOM hasta su uso práctico, y proporcionaremos código de muestra para practicar.

YouTube Video

typescript-html-shadow-dom.html
  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4  <meta charset="UTF-8">
  5  <title>TypeScript &amp; HTML</title>
  6  <style>
  7    * {
  8        box-sizing: border-box;
  9    }
 10
 11    body {
 12        margin: 0;
 13        padding: 1em;
 14        padding-bottom: 10em;
 15        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 16        background-color: #f7f9fc;
 17        color: #333;
 18        line-height: 1.6;
 19    }
 20
 21    .container {
 22        max-width: 800px;
 23        margin: 0 auto;
 24        padding: 1em;
 25        background-color: #ffffff;
 26        border: 1px solid #ccc;
 27        border-radius: 10px;
 28        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 29    }
 30
 31    h1, h2 {
 32        font-size: 1.2rem;
 33        color: #007bff;
 34        margin-top: 0.5em;
 35        margin-bottom: 0.5em;
 36        border-left: 5px solid #007bff;
 37        padding-left: 0.6em;
 38        background-color: #e9f2ff;
 39    }
 40
 41    button {
 42        display: block;
 43        margin: 1em auto;
 44        padding: 0.75em 1.5em;
 45        font-size: 1rem;
 46        background-color: #007bff;
 47        color: white;
 48        border: none;
 49        border-radius: 6px;
 50        cursor: pointer;
 51        transition: background-color 0.3s ease;
 52    }
 53
 54    button:hover {
 55        background-color: #0056b3;
 56    }
 57
 58    #output {
 59        margin-top: 1em;
 60        background-color: #1e1e1e;
 61        color: #0f0;
 62        padding: 1em;
 63        border-radius: 8px;
 64        min-height: 200px;
 65        font-family: Consolas, monospace;
 66        font-size: 0.95rem;
 67        overflow-y: auto;
 68        white-space: pre-wrap;
 69    }
 70
 71    .highlight {
 72        outline: 3px solid #ffc107; /* yellow border */
 73        background-color: #fff8e1;  /* soft yellow background */
 74        transition: background-color 0.3s ease, outline 0.3s ease;
 75    }
 76
 77    .active {
 78        background-color: #28a745; /* green background */
 79        color: #fff;
 80        box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
 81        transition: background-color 0.3s ease, box-shadow 0.3s ease;
 82    }
 83  </style>
 84</head>
 85<body>
 86    <div class="container">
 87        <h2>HTML Sample</h2>
 88        <div id="content"></div>
 89    </div>
 90
 91    <div class="container">
 92        <h1>JavaScript Console</h1>
 93        <button id="executeBtn">Execute</button>
 94        <div id="output"></div>
 95    </div>
 96
 97    <script>
 98        // Override console.log to display messages in the #output element
 99        (function () {
100            const originalLog = console.log;
101            console.log = function (...args) {
102                originalLog.apply(console, args);
103                const output = document.getElementById('output');
104                output.textContent += args.map(String).join(' ') + '\n';
105            };
106        })();
107
108        document.getElementById('executeBtn').addEventListener('click', () => {
109            // Prevent multiple loads
110            if (document.getElementById('externalScript')) return;
111
112            const script = document.createElement('script');
113            script.src = '/out/main.js';
114            script.id = 'externalScript';
115            //script.onload = () => console.log('typescript-html-shadow-dom.js loaded and executed.');
116            //script.onerror = () => console.log('Failed to load typescript-html-shadow-dom.js.');
117            document.body.appendChild(script);
118        });
119    </script>
120</body>
121</html>

Explicación Detallada y Guía Práctica Paso a Paso del Shadow DOM

Shadow DOM es uno de los componentes clave de los Web Components. Crea un árbol DOM encapsulado que separa el estilo y la estructura del componente del exterior. Aquí proporcionaremos una explicación detallada de los fundamentos del Shadow DOM hasta sus casos de uso prácticos, junto con código de ejemplo práctico.

¿Qué es el Shadow DOM?

Shadow DOM es una tecnología estándar web con las siguientes características.

  1. Encapsulación

    Shadow DOM separa la estructura DOM interna de un componente del exterior. Otros estilos y scripts no interfieren, mejorando la reutilización.

  2. Ámbito de Estilo Independiente

    Los estilos dentro del Shadow DOM no afectan al CSS externo. De manera similar, los estilos externos no se aplican dentro del Shadow DOM.

  3. Árbol DOM Aislado

    Shadow DOM existe como un árbol separado del DOM regular, con acceso restringido desde el DOM principal.

Uso Básico del Shadow DOM

El siguiente código es el primer ejemplo que utiliza Shadow DOM.

 1class MyElement extends HTMLElement {
 2  constructor() {
 3    super();
 4
 5    // Attach Shadow DOM
 6    const shadowRoot = this.attachShadow({ mode: 'open' });
 7
 8    // Add HTML and CSS inside Shadow DOM
 9    shadowRoot.innerHTML = `
10      <style>
11        p {
12          color: blue;
13          font-size: 18px;
14        }
15      </style>
16      <p>This is inside Shadow DOM!</p>
17    `;
18  }
19}
20
21// Register the custom element
22customElements.define('my-element', MyElement);
23
24document.getElementById('content').innerHTML = `
25  <my-element></my-element>
26`;
  • El navegador mostrará el texto azul: '¡Esto está dentro del Shadow DOM!'. El estilo de este texto no se ve afectado por el CSS externo.

Pasos básicos de Shadow DOM

Para usar Shadow DOM, como se muestra en este código, debes utilizar el método attachShadow en JavaScript. A continuación se detallan los pasos básicos:.

  1. Creación de Elementos Personalizados Un elemento personalizado es una etiqueta definida por el usuario que puedes crear además de las etiquetas estándar de HTML. En este paso, creas una clase que extiende de HTMLElement, como la clase MyElement, preparando al navegador para reconocerla como una nueva etiqueta. Al registrar la clase creada con customElements.define(), puedes usarla como una etiqueta personalizada en HTML.

  2. Incorporación del Shadow DOM Al ejecutar this.attachShadow() dentro de un elemento personalizado, puedes crear un Shadow DOM.

  3. Añadiendo HTML y CSS Dentro del Shadow DOM Dentro del Shadow DOM, puedes definir tu propia estructura HTML y estilos. Por ejemplo, al asignar HTML y CSS al innerHTML, puedes darle una apariencia y comportamiento independiente sin ser afectado por el CSS o HTML externo. Esto te permite crear componentes encapsulados.

Modos del Shadow DOM: open y closed

El Shadow DOM tiene dos modos: open y closed.

  • Modo abierto: El shadowRoot asociado al Shadow DOM puede ser accedido externamente.
  • Modo cerrado: El shadowRoot asociado al Shadow DOM no puede ser accedido externamente.

A continuación, hay un ejemplo de código que muestra las diferencias entre los dos modos.

 1class OpenElement extends HTMLElement {
 2  constructor() {
 3    super();
 4    this.attachShadow({ mode: 'open' }).innerHTML = `
 5      <p>Open Shadow DOM</p>
 6    `;
 7  }
 8}
 9
10class ClosedElement extends HTMLElement {
11  constructor() {
12    super();
13    this.attachShadow({ mode: 'closed' }).innerHTML = `
14      <p>Closed Shadow DOM</p>
15    `;
16  }
17}
18
19customElements.define('open-element', OpenElement);
20customElements.define('closed-element', ClosedElement);
21
22document.getElementById('content').innerHTML = `
23  <open-element></open-element>
24  <closed-element></closed-element>
25`;
26
27const openElement = document.querySelector('open-element') as OpenElement;
28console.log(openElement.shadowRoot); // ShadowRootが出力される
29
30const closedElement = document.querySelector('closed-element') as ClosedElement;
31console.log(closedElement.shadowRoot); // nullが出力される
  • Elegir el modo closed hace que la propiedad shadowRoot sea inaccesible.

Encapsulación de estilos utilizando Shadow DOM

Al usar Shadow DOM, puedes encapsular completamente los estilos dentro de tus componentes.

El siguiente ejemplo demuestra la separación entre los estilos globales y los estilos dentro del Shadow DOM.

 1class StyledElement extends HTMLElement {
 2  constructor() {
 3    super();
 4    const shadowRoot = this.attachShadow({ mode: 'open' });
 5
 6    shadowRoot.innerHTML = `
 7      <style>
 8        p {
 9          background-color: lightblue;
10          padding: 10px;
11          border: 1px solid blue;
12        }
13      </style>
14      <p>Shadow DOM Styled Content</p>
15    `;
16  }
17}
18
19customElements.define('styled-element', StyledElement);
20
21document.getElementById('content').innerHTML = `
22  <style>
23    p {
24      color: red;
25      font-weight: bold;
26    }
27  </style>
28
29  <styled-element></styled-element>
30`;
  • El p dentro del Shadow DOM no se ve afectado por los estilos globales y aplica sus propios estilos.

Ejemplo práctico de Shadow DOM: Tooltip personalizado

A continuación, presentamos un ejemplo de cómo crear un tooltip personalizado utilizando Shadow DOM.

 1class Tooltip extends HTMLElement {
 2  constructor() {
 3    super();
 4
 5    const shadowRoot = this.attachShadow({ mode: 'open' });
 6
 7    shadowRoot.innerHTML = `
 8      <style>
 9        :host {
10          position: relative;
11          display: inline-block;
12          cursor: pointer;
13        }
14
15        .tooltip {
16          visibility: hidden;
17          background-color: black;
18          color: white;
19          text-align: center;
20          padding: 5px;
21          border-radius: 5px;
22          position: absolute;
23          bottom: 125%;
24          left: 50%;
25          transform: translateX(-50%);
26          white-space: nowrap;
27        }
28
29        :host(:hover) .tooltip {
30          visibility: visible;
31        }
32      </style>
33      <slot></slot>
34      <div class="tooltip">Tooltip text</div>
35    `;
36  }
37}
38
39customElements.define('custom-tooltip', Tooltip);
40
41document.getElementById('content').innerHTML = `
42  <custom-tooltip>
43    Hover over me
44    <span slot="tooltip">This is a custom tooltip!</span>
45  </custom-tooltip>
46`;
  • Este código crea un tooltip personalizado y muestra un tooltip con estilo al pasar el cursor.

Resumen

El Shadow DOM es una tecnología crucial para los Web Components, ya que proporciona un DOM encapsulado y un alcance de estilo. Aquí, cubrimos los conceptos básicos del Shadow DOM, su uso, diferencias de modos, encapsulación de estilos y ejemplos prácticos. Aprovechando esto, puedes construir componentes reutilizables y robustos.

Puedes seguir el artículo anterior utilizando Visual Studio Code en nuestro canal de YouTube. Por favor, también revisa nuestro canal de YouTube.

YouTube Video