> For the complete documentation index, see [llms.txt](https://docs.wem.io/platform/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.wem.io/platform/tutorials/building-widgets/wemscript/11-css-attachshadow.md).

# 11. CSS - attachShadow

Finally, we no longer have to worry about naming collisions and overwriting other code when using ES Modules. We can use generic class names like `Button` or `Note` without adding extra noise to our code, making it much more enjoyable to read and write. However, is there a similar solution for CSS, like CSS Modules? Unfortunately, no. Nevertheless, the W3C seems to be working on it.

This is unfortunate, as we have found a way to encapsulate JavaScript code from other widgets, but our CSS still lacks this capability. However, there is a solution: we can style elements programmatically within JavaScript. While you can style elements using `element.style.propertyName`, a better approach is to use Web Components with the Shadow DOM.

If we modify the code of our Note widget to utilize the Shadow DOM, it would look something like this:

```javascript
class Note {
	constructor({ x = 100, y = 100, message = "New note" }) {
        this.setThisContext();

        const handleBarEl = document.createElement("div");
        handleBarEl.classList.add("handle-bar");
        handleBarEl.addEventListener("mousedown", this.startDragHandler);

        this.messageEl = document.createElement("textarea");
        this.messageEl.classList.add("message");
        this.messageEl.value = message;

        const sheet = new CSSStyleSheet();
        sheet.replaceSync(`
			:host {
				background-color: lightgoldenrodyellow;
				display: flex;
				flex-direction: column;
                position: fixed;
                left: calc(var(--x) * 1px);
                top: calc(var(--y) * 1px);
                width: 250px;
                height: 250px;
            }

            .handle-bar {
                background-color: var(--handle-bar-color, tomato);
                cursor: pointer;
                flex: 0 0 20px;
            }

            .message {
                flex: 1 0;
                outline: none;
                padding: 8px;
                resize: none;
            }
        `);

        this.rootEl = document.createElement("div");

        const shadow = this.rootEl.attachShadow({ mode: "open" });
        shadow.append(handleBarEl, this.messageEl);
        shadow.adoptedStyleSheets.push(sheet);

        this.updatePosition(x, y);
    }
}
```

In this code, we use `CSSStyleSheet` and call the `replaceSync()` method to set the CSS. As you can see, we use very generic class names like `.message`. This is the power of the Shadow DOM; we don't need to use selectors like `.wem-academy-note > .message` to avoid collisions with other selectors.

The final step is to create the Shadow DOM and append our `CSSStyleSheet` instance to it. We accomplish this with the `attachShadow()` method available on an `HTMLElement`. This method returns a `ShadowRoot`, which is a special type of DOM node but provides the familiar DOM manipulation methods, such as `shadow.append(handleBarEl, this.messageEl)`, which we use to append the handle bar and message box. Next, we use `shadow.adoptedStyleSheets.push(sheet)` to attach the CSS to this Shadow DOM.

That's about it! You can see that there are several ways to style elements, each with its pros and cons. It is up to you to choose the one that best fits your needs. Hopefully, the W3C will expedite the development of CSS Modules, as that would seem like the optimal solution.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.wem.io/platform/tutorials/building-widgets/wemscript/11-css-attachshadow.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
