Shadow DOM dalam JavaScript

Shadow DOM dalam JavaScript

Artikel ini menjelaskan tentang Shadow DOM dalam 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 &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 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>

Memahami Shadow DOM

Shadow DOM adalah fitur kuat dari standar Web Components yang memungkinkan enkapsulasi gaya dan struktur DOM di dalam komponen. Fitur ini mencegah gangguan dari gaya dan skrip antara komponen dan dokumen utama.

Shadow DOM dalam JavaScript

Shadow DOM menyediakan cara untuk membuat pohon DOM yang dibatasi terkait dengan elemen DOM biasa. Pohon bayangan ini terisolasi dari keseluruhan dokumen, di mana gaya dan skrip eksternal tidak mempengaruhinya, serta gaya dan skrip internalnya tidak bocor keluar.

Sebagai contoh, jika Anda membuat komponen tombol kustom menggunakan Shadow DOM, gaya-gayanya tidak akan mengganggu elemen lain di halaman. Demikian pula, elemen dengan nama kelas yang sama tidak akan konflik.

Konten HTML biasa yang berada di luar Shadow DOM disebut sebagai Light DOM.

Manfaat Shadow DOM

  1. Enkapsulasi

    • Shadow DOM memisahkan gaya dan fungsi, sehingga mencegah konflik dengan gaya dan skrip global.
  2. Dapat digunakan kembali

    • Komponen yang dibangun dengan Shadow DOM dapat digunakan kembali di berbagai proyek tanpa khawatir terjadi konflik gaya.
  3. Mudah dipelihara

    • Enkapsulasi membuat logika dan gaya komponen menjadi terpisah, sehingga debugging dan pemeliharaan menjadi lebih mudah.

Membuat Shadow DOM

Untuk menggunakan Shadow DOM, Anda perlu melampirkan shadow root ke elemen HTML. Berikut adalah contoh sederhana:.

1// Select the host element
2const hostElement = document.querySelector('#shadow-host');
3
4// Attach a shadow root
5const shadowRoot = hostElement.attachShadow({ mode: 'open' });

Penjelasan

Kode ini mencakup elemen-elemen berikut:.

  1. Elemen Host

    • Sebuah elemen DOM biasa yang menjadi tempat menempelkan shadow root (dalam hal ini, #shadow-host).
  2. Shadow Root

    • Root dari pohon shadow yang dibuat menggunakan attachShadow.
  3. Mode

    • Dalam mode open, JavaScript eksternal dapat mengakses shadow root melalui element.shadowRoot. Di sisi lain, mode closed tidak mengizinkan akses.

Pemformatan dalam Shadow DOM

Shadow DOM memiliki lingkup gaya sendiri. Gaya yang ditentukan dalam pohon shadow hanya berlaku untuk elemen-elemen dalam pohon tersebut. Berikut adalah contohnya:.

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`;

Meskipun terdapat konflik gaya pada dokumen utama, paragraf di dalam pohon shadow tidak akan terpengaruh.

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`;
  • Paragraf di dalam Shadow DOM tetap berwarna hijau, sedangkan yang di luar berwarna merah.

Event di dalam Shadow DOM

Event di dalam Shadow DOM mirip dengan event DOM biasa tetapi dapat berperilaku berbeda dalam hal propagasi karena enkapsulasi.

Berikut adalah contohnya:.

 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});
  • Ketika tombol diklik, kedua listener terpicu, menunjukkan perilaku bubbling event.
  • Ketika sebuah event yang berasal dari dalam Shadow DOM naik ke Light DOM, target event tersebut diubah menjadi elemen host, bukan sumber aslinya.
    • Dalam contoh ini, event.target di dalam Shadow DOM adalah elemen button yang sebenarnya, tetapi di luar Shadow DOM, itu digantikan dengan elemen host div.

Shadow DOM dan Elemen Kustom

Shadow DOM dan elemen kustom adalah komponen utama dari Web Components. Mereka adalah teknologi yang digunakan untuk membuat komponen UI yang dapat digunakan kembali dan terenkapsulasi.

 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);

Dokumen utama berisi HTML seperti berikut:.

1<my-card></my-card>
  • Dengan menggunakan Shadow DOM di dalam elemen kustom, Anda dapat membuat komponen yang dapat digunakan kembali dan tahan terhadap konflik gaya. Dalam kode ini, sebuah tag bernama my-card dibuat dan dikaitkan dengan kelas MyCard. Elemen <p> di dalam my-card tidak terpengaruh oleh gaya eksternal dan selalu ditampilkan dalam warna biru.

Slot: Mendistribusikan Konten Light DOM

Slot memungkinkan Anda menampilkan konten Light DOM ke dalam Shadow DOM. Berikut adalah contohnya:.

 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);

Dokumen utama berisi HTML seperti berikut:.

1<my-element>
2    <h3 slot="header">Header Content</h1>
3    <p slot="content">Main Content</p>
4</my-element>
  • Elemen slot di dalam Shadow DOM akan menampilkan konten Light DOM yang memiliki atribut slot yang sesuai.

Kesimpulan

Shadow DOM adalah alat penting untuk membangun komponen web yang kuat, dapat digunakan kembali, dan mudah dikelola. Dengan mengen kapsulasi gaya dan fungsionalitas, ini mengurangi potensi konflik dan menyederhanakan pengelolaan kode.

Anda dapat mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Silakan periksa juga saluran YouTube kami.

YouTube Video