Skip to Content
Course content
Click on the "Edit" button in the top corner of the screen to edit your slide content.

Think about a microwave in your kitchen. On the outside, you have a few buttons: "Start," "Stop," and maybe a dial for the timer. That's the interface you interact with. But inside that plastic shell, there's a chaotic mess of wires, a transformer, and a magnetron. You don't see those things, and more importantly, you can't accidentally touch them while you're just trying to heat up some leftover pizza. The shell protects the internals from you, and it protects you from the internals.

The Shadow DOM is essentially that plastic shell for your HTML. It allows you to attach a separate, hidden DOM tree to an element. This "shadow tree" is isolated from the main document, meaning the CSS and JavaScript you write for the rest of your page won't accidentally break the internals of your component, and the component's internal styles won't leak out and ruin your layout.

Breaking the Wall with attachShadow

To create this isolation, we use a method called attachShadow(). You call this on a standard HTML element (the "Shadow Host"), and it returns a "Shadow Root." Anything you append to that root stays inside the bubble.

I'll show you how this looks in practice. Let's say we're building a custom <user-card> component. We want it to have its own specific styling that never clashes with the rest of the app, regardless of what the global CSS says.

class UserCard extends HTMLElement {
  constructor() {
    super();
    // This is where the magic happens. 
    // 'mode: open' means we can still access the shadowRoot via JavaScript.
    const shadow = this.attachShadow({ mode: 'open' });

    const wrapper = document.createElement('div');
    wrapper.classList.add('card-wrapper');
    
    wrapper.innerHTML = `
      
      

User: Software Engineer

`; shadow.appendChild(wrapper); } } customElements.define('user-card', UserCard);

In this example, the <p> tag is styled to be royal blue. If you have a global CSS rule in your main index.css that says p { color: red; }, the text inside our <user-card> will stay blue. It's completely immune to the global styles.

The "Open" vs "Closed" Debate

You noticed I used { mode: 'open' }. You might wonder why we even have a choice. If you set it to 'closed', the element's shadowRoot property returns null. It essentially locks the door from the inside.

Between us, you'll almost always want 'open'. Closing the shadow DOM provides a false sense of security and makes debugging a nightmare. Very few production libraries actually use 'closed' because it interferes with testing tools and accessibility audits. Stick with open.

Piercing the Bubble

Now, if the Shadow DOM is a wall, how do we let a little bit of information through? We use CSS Custom Properties (CSS variables). These are one of the few things that can "pierce" the shadow boundary.

If I change my internal style to color: var(--card-color, royalblue);, I'm telling the component: "Use the variable --card-color if it exists; otherwise, default to royalblue." Now, the developer using my component can change the color from their global CSS file like this:

<style>
  user-card {
    --card-color: orange;
  }
</style>

This is the professional way to handle components. You encapsulate the logic and structure, but you leave a few "knobs" (variables) on the outside for the user to tweak.




📋 Practical Task

Build an Isolated Notification Toast Component

Your task is to create a custom HTML element called <notification-toast> using the Shadow DOM. The goal is to ensure that the toast's styling is completely isolated from the rest of the page.

Requirements:

  • Create a class NotificationToast that extends HTMLElement.
  • Use attachShadow({ mode: 'open' }) to create a shadow root.
  • Inside the shadow root, add a <div> with a class of "toast-container".
  • Add a <style> block inside the shadow root that gives the .toast-container a background color of #333, text color of white, padding of 1rem, and a fixed position at the top-right of the screen.
  • The toast should display the text: "System Update Complete!"
  • Use a CSS variable --toast-bg for the background color, defaulting to #333 if the variable isn't provided.
  • Register the component using customElements.define.

Testing your work: Add a global CSS rule to your page: div { background: red !important; }. If your toast remains the specified color and doesn't turn red, you've successfully implemented the Shadow DOM.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.