Shadow DOM em JavaScript
Este artigo explica o Shadow DOM em JavaScript.
YouTube Video
javascript-html-shadow-dom.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>JavaScript & 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 id="shadow-host">Shadow Root Element</div>
90 <my-card></my-card>
91 </div>
92
93 <div class="container">
94 <h1>JavaScript Console</h1>
95 <button id="executeBtn">Execute</button>
96 <div id="output"></div>
97 </div>
98
99 <div>
100 <h2>Slot Sample</h2>
101 <my-element>
102 <h3 slot="header">Header Content</h1>
103 <p slot="content">Main Content</p>
104 </my-element>
105 </div>
106
107 <script>
108 // Override console.log to display messages in the #output element
109 (function () {
110 const originalLog = console.log;
111 console.log = function (...args) {
112 originalLog.apply(console, args);
113 const output = document.getElementById('output');
114 output.textContent += args.map(String).join(' ') + '\n';
115 };
116 })();
117
118 document.getElementById('executeBtn').addEventListener('click', () => {
119 // Prevent multiple loads
120 if (document.getElementById('externalScript')) return;
121
122 const script = document.createElement('script');
123 script.src = 'javascript-html-shadow-dom.js';
124 script.id = 'externalScript';
125 //script.onload = () => console.log('javascript-html-shadow-dom.js loaded and executed.');
126 //script.onerror = () => console.log('Failed to load javascript-html-shadow-dom.js.');
127 document.body.appendChild(script);
128 });
129 </script>
130</body>
131</html>Entendendo o Shadow DOM
Shadow DOM é uma funcionalidade poderosa do padrão Web Components que permite a encapsulação de estilos e da estrutura DOM dentro dos componentes. Essa funcionalidade impede a interferência de estilos e scripts entre os componentes e o documento principal.
Shadow DOM em JavaScript
Shadow DOM oferece uma maneira de criar uma árvore DOM com escopo associada a um elemento DOM regular. Essa árvore de sombra é isolada do documento geral, onde estilos e scripts externos não a influenciam, nem seus estilos e scripts internos vazam para fora.
Por exemplo, se você criar um componente de botão personalizado usando Shadow DOM, seus estilos não interferirão com outros elementos na página. Da mesma forma, elementos com o mesmo nome de classe não entrarão em conflito.
O conteúdo HTML comum fora do Shadow DOM é chamado de Light DOM.
Benefícios do Shadow DOM
-
Encapsulamento
- O
Shadow DOMsepara estilo e funcionalidade, impedindo conflitos com estilos e scripts globais.
- O
-
Reutilização
- Componentes construídos com o
Shadow DOMpodem ser reutilizados em diferentes projetos sem se preocupar com conflitos de estilo.
- Componentes construídos com o
-
Manutenção
- O encapsulamento torna a lógica e o estilo do componente autônomos, facilitando a depuração e a manutenção.
Criando o Shadow DOM
Para usar o Shadow DOM, você precisa anexar uma raiz de sombra a um elemento HTML. Aqui está um exemplo simples:.
1// Select the host element
2const hostElement = document.querySelector('#shadow-host');
3
4// Attach a shadow root
5const shadowRoot = hostElement.attachShadow({ mode: 'open' });Explicação
Este código inclui os seguintes elementos:.
-
Elemento Host
- Um elemento DOM comum ao qual a raiz do shadow é anexada (neste caso,
#shadow-host).
- Um elemento DOM comum ao qual a raiz do shadow é anexada (neste caso,
-
Raiz Shadow
- A raiz da árvore shadow criada usando
attachShadow.
- A raiz da árvore shadow criada usando
-
Modo
- No modo
open, JavaScript externo pode acessar a raiz shadow viaelement.shadowRoot. Por outro lado, o modoclosednão permite acesso.
- No modo
Estilizando dentro do Shadow DOM
O Shadow DOM possui seu próprio escopo de estilo. Os estilos definidos dentro da árvore do Shadow aplicam-se apenas aos elementos dentro dessa árvore. Aqui está um exemplo:.
1// Add content to the shadow root
2shadowRoot.innerHTML = `
3 <style>
4 p {
5 color: green;
6 }
7 </style>
8 <p>Scoped style inside Shadow DOM.</p>
9`;Mesmo que haja estilos conflitantes no documento principal, eles não afetam o parágrafo dentro da árvore shadow.
1const content = document.getElementById('content');
2content.innerHTML = `
3 <style>
4 p {
5 color: red;
6 }
7 </style>
8 <p>This is in the main DOM.</p>
9`;- O parágrafo dentro do
Shadow DOMpermanece verde, enquanto o externo é vermelho.
Eventos dentro do Shadow DOM
Eventos dentro do Shadow DOM são semelhantes aos eventos regulares do DOM, mas podem se comportar de maneira diferente em termos de propagação devido à encapsulação.
Aqui está um exemplo:.
1// Add an event listener inside Shadow DOM
2shadowRoot.innerHTML = `
3 <div id="button-container">
4 <button id="shadow-button">Click Me</button>
5 </div>
6`;
7
8shadowRoot.querySelector('#shadow-button').addEventListener('click', (event) => {
9 console.log('Button : Button clicked inside Shadow DOM');
10 console.log(event.target);
11});
12
13shadowRoot.querySelector('#button-container').addEventListener('click', (event) => {
14 console.log('Container : Button clicked inside Shadow DOM');
15 console.log(event.target);
16});
17
18hostElement.addEventListener('click', (event) => {
19 console.log('Event bubbled to the host element');
20 console.log(event.target);
21});
22
23document.addEventListener('click', (event) => {
24 console.log('Document listener');
25 console.log(event.target);
26});- Quando o botão é clicado, ambos os ouvintes são acionados, demonstrando o comportamento de propagação de eventos.
- Quando um evento originado dentro do
Shadow DOMsobe para oLight DOM, otargetdo evento é reescrito para o elemento host em vez da fonte original.- Neste exemplo, o
event.targetdentro doShadow DOMé o elementobuttonreal, mas fora doShadow DOM, ele é substituído pelo elemento hostdiv.
- Neste exemplo, o
Shadow DOM e Elementos Personalizados
Shadow DOM e elementos personalizados são componentes chave de Web Components. São tecnologias usadas para criar componentes de interface reutilizáveis e encapsulados.
1class MyCard extends HTMLElement {
2 constructor() {
3 super();
4 const shadow = this.attachShadow({ mode: 'open' });
5 shadow.innerHTML = `
6 <style>
7 p {
8 color: blue;
9 }
10 </style>
11 <p>I'm inside shadow DOM</p>
12 `;
13 }
14}
15
16customElements.define('my-card', MyCard);O documento principal contém HTML assim:.
1<my-card></my-card>- Ao usar o
Shadow DOMdentro de elementos personalizados, é possível criar componentes reutilizáveis que são resistentes a conflitos de estilo. Neste código, uma tag chamadamy-cardé criada e associada à classeMyCard. O elemento<p>dentro demy-cardnão é afetado por estilos externos e sempre é exibido em azul.
Slots: Distribuindo Conteúdo do Light DOM
Slots permitem projetar conteúdo do Light DOM dentro do Shadow DOM. Aqui está um exemplo:.
1class MyElement extends HTMLElement {
2 constructor() {
3 super();
4 const shadow = this.attachShadow({ mode: 'open' });
5
6 shadow.innerHTML = `
7 <style>
8 .container {
9 border: 2px solid #ccc;
10 padding: 16px;
11 border-radius: 8px;
12 font-family: sans-serif;
13 }
14 .header {
15 font-size: 1.2em;
16 color: darkblue;
17 margin-bottom: 8px;
18 }
19 .content {
20 font-size: 1em;
21 color: #333;
22 }
23 </style>
24 <div class="container">
25 <div class="header">
26 <slot name="header"></slot>
27 </div>
28 <div class="content">
29 <slot name="content"></slot>
30 </div>
31 </div>
32 `;
33 }
34}
35
36customElements.define('my-element', MyElement);O documento principal contém HTML assim:.
1<my-element>
2 <h3 slot="header">Header Content</h1>
3 <p slot="content">Main Content</p>
4</my-element>- O elemento
slotdentro doShadow DOMexibe o conteúdo doLight DOMque possui o atributoslotcorrespondente.
Conclusão
O Shadow DOM é uma ferramenta essencial para construir componentes web robustos, reutilizáveis e de fácil manutenção. Ao encapsular estilos e funcionalidades, ele reduz o potencial de conflitos e simplifica a gestão do código.
Você pode acompanhar o artigo acima usando o Visual Studio Code em nosso canal do YouTube. Por favor, confira também o canal do YouTube.