# Shadow DOM

Shadow DOM is a web standard that offers component style and markup encapsulation. It is a critical piece of the Web Components story. It allows you to attach a hidden, separated DOM tree to an element.

## 1. Why do we need it?

In the standard DOM, everything is global.
*   **CSS Leaks:** A style defined for `h1` affects every `h1` on the page.
*   **ID Conflicts:** `id="container"` must be unique across the entire page.
*   **Fragility:** JavaScript can accidentally select elements inside a widget and break it.

Shadow DOM solves this by creating a "scoped" subtree.

## 2. Terminology

*   **Shadow Host:** The regular DOM node that the shadow DOM is attached to.
*   **Shadow Tree:** The DOM tree inside the Shadow DOM.
*   **Shadow Boundary:** The place where the shadow DOM ends, and the regular DOM begins.
*   **Shadow Root:** The root node of the shadow tree.

## 3. Creating Shadow DOM

You create a shadow root using `element.attachShadow()`.

```javascript
const host = document.querySelector('#host');
const shadowRoot = host.attachShadow({ mode: 'open' });

shadowRoot.innerHTML = `
  <style>
    p { color: red; } /* Only affects paragraphs inside this shadow root */
  </style>
  <p>I am in the shadows!</p>
`;
```

## 4. Encapsulation

### CSS Isolation
Styles defined inside the Shadow DOM do not leak out. Styles defined outside do not leak in (mostly).
*   *Exception:* Inheritable properties (like `color`, `font-family`) still trickle down from the host.

### DOM Isolation
`document.querySelector('p')` will **not** find the paragraph inside the shadow root. To access it, you must go through the shadow root: `host.shadowRoot.querySelector('p')`.

## 5. Open vs. Closed Mode

When attaching a shadow root, you specify a mode.

*   **`open`:** You can access the shadow root using `element.shadowRoot`.
    ```javascript
    const root = host.attachShadow({ mode: 'open' });
    console.log(host.shadowRoot); // Returns the ShadowRoot object
    ```
*   **`closed`:** `element.shadowRoot` returns `null`. This makes it harder (but not impossible) for outside JS to access the internal DOM.
    ```javascript
    const root = host.attachShadow({ mode: 'closed' });
    console.log(host.shadowRoot); // null
    ```
    *Note: Closed mode is rarely used because it prevents even your own code from easily accessing the root, and it doesn't offer true security.*

## 6. Event Retargeting

When an event bubbles up from the Shadow DOM to the Light DOM (the regular page), its `target` is adjusted to look like it came from the **Shadow Host**.

*   **Inside Shadow DOM:** Target is the specific button clicked.
*   **Outside Shadow DOM:** Target is the `<my-component>` host element.

This preserves encapsulation; the outside world doesn't need to know about the internal structure.

[[programming/javascript/vanilla/javascript]]
[[programming/javascript/vanilla/web-components]]
[[programming/javascript/vanilla/dom-manipulation]]