Roma’s Unpolished Posts

Shadow DOM on Regular Elements

Published on:
Categories:
Shadow DOM, Custom Elements
Current drink:
Yunnan tea

For some reason, I had this misconception that Shadow DOM could not be used with regular elements, I only ever tried it with the custom ones. But — thanks to Doug Parker, who did point it out to me on Mastodon, — now I know that we can actually do that.

I knew that custom elements (or Web Components) without Shadow DOM were a thing (see also a related article Blinded By the Light DOM by Eric Meyer from yesterday), but it never occurred to me that in the same way we could attach a Shadow DOM to a web component, we could do it just for a regular element. Sometimes it is very easy to overlook simple things!

Curiously, if only I had read the MDN docs about Using shadow DOM (the link Doug gave me), then I would’ve learned that.

Declarative Shadow DOM

Even more, in another Mastodon post, Doug shows how the Declarative Shadow DOM can also be used with regular elements. If only Firefox would support it! (It actually will, rather soon — they did state that the implementation will start soon! Follow this bugzilla ticket if you’d like to track this).

The Context

Where would I want to use Shadow DOM on a regular element? The case that resulted in this post was me wishing for a particular thing in HTML. Let me quote my own mastodon post:

What if we had an #HTML attribute that would make an element “invisible” for #CSS selectors?

Like display: contents, but for DOM.

Like,

<div class="foo">
	<div i-am-not-here>
		<div class="bar">
		</div>
	</div>
</div>

And then .foo > .bar would actually select the inner .bar?

I can see something like this being very useful for #WebComponents, among other things, as right now it is not possible to use them as generic wrappers without impact.

Playing with Shadow DOM and custom elements, I found two ways to achieve what I wanted.

Here are both CodePens:

The one using a custom element is a bit weird. But it works! But I probably won’t use it in production, as it looks very fragile, requires JavaScript, and is hard to make a fallback from.

The second one, with the Declarative Shadow DOM, is much nicer. It is still a bit verbose — I think I would still prefer some way of doing this kind of “transparent” element just via an attribute — but it is much less weird. If only we had Firefox support… Maybe I’ll look into using a ponyfill for this?

But what I did like is that the fallback is very gracious: the only difference outside the Shadow DOM applying is that the template stays in the DOM, impacting CSS selectors like :nth-child() etc. But any other selectors like the .foo > .bar from the CodePen would continue working.

Why Do I Want This

In short: to be able to use Web Components as something like “Higher-Order Components”, where they could provide their functionality (JS or via custom CSS properties that would get inherited into the light DOM, as seen in the example) to the nested elements, but without any impact on layout (when using display: contents) or selectors (the thing that I wanted it to be originally).

Here is another CodePen with a bit more expanded use case, though I understand that it might still not be “practical”.

But hey, this is just a quick article in which I wanted to share my observation — this is a thing that I want to start doing more of. Maybe when I play with this further, I will write another post with better examples!

Or, maybe what I shared today would inspire you to do something interesting. Let me know!

By the Way

So far, I have posted for every day in November! “Is this a NaBloPoMo?” — He asks, pointing at a butterfly. We will see! I doubt I could keep it up through the whole month, but maybe? I just need to choose a tiny topic and not be a perfectionist about polishing it completely. “Just”. See you in the next post, be it tomorrow or later!

Please share your thoughts about this on Mastodon!