Declara­tive custom ele­ments with shadow­root attri­bute on template element

To get started run this JS line on your devtools console to check for its feature support

On Chrome, if it returns false, you can open this chrome://flags/#enable-experimental-web-platform-features on your Chrome address bar, enable it and restart your browser to try again.

This page uses the polifyll mentioned in the original article where I learned about the feature

tlrd;

Stylesheet affects all elements globally by default but using template shadowroot attribute on a custom element we can scope the styles without JS in a way it won't inherit styles from its parent elements and its internal styles won't affect elements outside the shadowroot boundaries avoiding style collisions with third-parties

How to avoid global style inheritance

If we want to completely ignore global styles, we start by not using <slot> inside <template> elements

Result:

The styles are vanished and you should be looking at the browser default styles

<slot> and its global CSS inheritance

When using slot inside template, be aware slots inherit styles from its parent element's styles. So let's start with an example

The result is as follow

All the styles applied to the form are global styles on this page, this is exactly what we want to have control over. Whenever we use slot the element used with it inherit parent styles

I bit of scoped CSS

Lets add some <style> in a way that only our scoped element is going to take advantage of the style

Result:

The take away from this example, is how general is the selector used to target the form element.

Custom Properties to rule them all

We can define custom properties and document the ones our custom element uses internally, so people can override them on the :host element

Result:

In this way if the global escope wants to change the custom element scoped CSS, we can do so by targeting the host element and overriding its custom properties

Result:

Link stylesheet

There's also a possibility to instead of using <style> we use a <link rel="stylesheet">, So, rewriting the example above with an external stylesheet it looks like this:

custom-form.css

HTML Markup

One possibly advatange of using an external stylesheet is that the style within it doesn't get repeated on each ocasion it occurs in our markup. If there's two forms, we need to be careful about the markup but we can almost forget the style

Result:

Scoped CSS with HTML only

The main perk of this API is the possibility to scope CSS without any JavaScript,
because we know there's a precious delay while a JS loads to customElements.define the markup, and usually appendChild a chunk of CSS to style the element as well

The less network and less JS runtime envolved, the better it leads to faster perceived performance on load. Cause the HTML and Styles are there in the critical rendering path.

When there's two buttons in the screen

On this page I use declarative shadowroot on <ce-code> on each ocurrence of code highlight to avoid global style collisions, my HTML looks like this:

Even though I have multiple mention to the same external stylesheet, it loads once and works as expected for all <ce-code> templates

Wishful thinking

I presented how the API works in a way I can understand it, now, I list some of my opnions which I think can contribute to the development and discussion of these API on the web platform

Cons

Pro

Ideally

Thoughts

The possibility to scope CSS from its global inheritance avoiding collisions is HOT 🔥 but, WHAT IF, we could tell CSS how to rearrange its own inheritance using a property?

If there's a clean separation of concerns

Why would we need HTML or JS, to tell CSS it may ignore inheritance of parent styles?