✱ Asterisco: Open vs Closed en Shadow DOM

¿Qué diferencia hay entre marcar un Shadow DOM usando open o closed en el modo? Esta es una pregunta a la que buscamos la respuesta en este capítulo.

Cuando trabajamos con shadow DOM en JavaScript, una de las decisiones importantes que debemos tomar es si nuestro shadow root será abierto (open) o cerrado (closed). Esta elección afecta directamente a cómo podemos acceder y manipular el contenido encapsulado dentro de nuestro componente.

Por defecto, cuando creamos un shadow DOM con open, el objeto shadowRoot queda accesible desde fuera del componente. Esto significa que si hacemos un document.querySelector para obtener nuestro custom element, luego podemos acceder a su shadowRoot y manipular sus nodos internos. Por ejemplo, podríamos ver los hijos que contiene y modificar su estructura o estilos. Esto puede ser útil para depuración o para extender funcionalidades, pero también abre la puerta a que otros scripts externos puedan hackear o alterar el componente desde fuera, algo que a veces queremos evitar.

Para ilustrar esto, imaginemos que tenemos un elemento llamado dis y hacemos:

const dis = document.querySelector('mi-elemento');
console.log(dis.shadowRoot); // Nos devuelve el shadow root real

Podemos acceder a los nodos hijos y modificar el contenido, lo que puede ser un problema si queremos mantener la encapsulación estricta.

Para dificultar este acceso, podemos crear el shadow DOM con la opción closed. En este caso, aunque el shadow root se crea y funciona internamente, la propiedad shadowRoot del elemento será null. Esto significa que no podremos acceder directamente desde fuera al contenido interno del shadow DOM usando esa propiedad.

Si intentamos hacer lo mismo que antes con un shadow root cerrado:

const dis = document.querySelector('mi-elemento');
console.log(dis.shadowRoot); // null

No tendremos acceso directo, aunque el shadow DOM sigue existiendo y funcionando normalmente. Para manipular el contenido interno, tendremos que guardar la referencia al shadow root en una variable privada dentro del componente cuando lo creamos, por ejemplo:

class MiElemento extends HTMLElement {
  constructor() {
    super();
    this._root = this.attachShadow({ mode: 'closed' });
    // Ahora usamos this._root para manipular el shadow DOM internamente
  }

  agregarContenido() {
    const p = document.createElement('p');
    p.textContent = 'Hola desde shadow DOM cerrado';
    this._root.appendChild(p);
  }
}
customElements.define('mi-elemento', MiElemento);

Aquí, aunque desde fuera no podamos acceder a shadowRoot, internamente seguimos teniendo la referencia para trabajar con el contenido.

Es importante destacar que, aunque el modo closed dificulta el acceso externo, no es una seguridad absoluta. JavaScript no tiene aún un sistema de variables privadas completamente maduro para este caso, aunque las nuevas versiones del lenguaje están introduciendo variables privadas en clases con una sintaxis específica (como el prefijo #). Además, existen técnicas avanzadas como usar símbolos o WeakMap para simular privacidad, pero nada impide que alguien con acceso al código pueda intentar manipular el componente si realmente quiere.

En la práctica, muchos navegadores usan shadow DOM cerrado para sus propios elementos nativos, como la etiqueta <video>, para evitar que los usuarios modifiquen su estructura interna y mantengan la integridad visual y funcional del navegador.

Sin embargo, para la mayoría de los casos en los que estamos creando nuestros propios componentes, usar open suele ser suficiente y más cómodo, porque facilita la depuración y la extensión. Además, hay que tener en cuenta que, al final, cualquier usuario puede modificar el DOM de una página con las herramientas de desarrollo del navegador, así que el modo cerrado no es una barrera definitiva contra la manipulación externa.

La verdadera ventaja del shadow DOM no está en impedir que alguien acceda al contenido desde fuera, sino en evitar que otros estilos o scripts de la página afecten a cómo se visualiza y funciona nuestro componente. La encapsulación visual y funcional es lo que realmente aporta valor.

Por lo tanto, la elección entre open y closed dependerá del nivel de encapsulación y control que queramos tener sobre nuestro componente. Para proyectos donde la privacidad interna es crítica, closed puede ser la opción adecuada. Para otros donde la flexibilidad y la facilidad de acceso son prioritarias, open será suficiente.

Nosotros, por ahora, seguiremos utilizando open para mantener la simplicidad y poder acceder cómodamente al shadow root durante el desarrollo y la depuración. Pero es bueno conocer ambas opciones y entender sus implicaciones para tomar la mejor decisión según el contexto.

Lista de reproducción
  1. 1
    ¿Por qué existe la tecnología Web Components?
    13 minutos
  2. 2
    Tu primer Web Component
    19 minutos
  3. 3
    La etiqueta template de HTML5
    13 minutos
  4. 4
    ✱ Asterisco: Documentos DOM
    5 minutos
  5. 5
    Custom Elements usando HTML Templates
    9 minutos
  6. 6
    ✱ Asterisco: Microframeworks y JSX
    9 minutos
  7. 7
    Shadow DOM
    7 minutos
  8. 8
    Slots de Shadow DOM
    7 minutos
  9. 9
    ✱ Asterisco: Open vs Closed en Shadow DOM
    5 minutos
  10. 10
    Customized built-in elements
    14 minutos
  11. 11
    Polyfills para Web Components
    9 minutos
  12. 12
    ✱ Asterisco: The end... por el momento
    6 minutos
  13. 13
    ✱ Asterisco: Todo sigue igual (2020)
    6 minutos