Hacker News new | past | comments | ask | show | jobs | submit login
Demystifying the Shadow DOM (thetshaped.dev)
46 points by thunderbong 66 days ago | hide | past | favorite | 50 comments



There are significantly more drawbacks to Shadow DOM than this stub of an article suggests.

To the point that even the people working on Web Components finally admitted that in 2022: https://w3c.github.io/webcomponents-cg/2022.html

--- start quote ---

It's worth noting that many of these pain points are directly related to Shadow DOM's encapsulation. While there are many benefits to some types of widely shared components to strong encapsulation, the friction of strong encapsulation has prevented most developers from adopting Shadow DOM, to the point of there being alternate proposals for style scoping that don't use Shadow DOM. We urge browser vendors to recognize these barriers and work to make Shadow DOM more usable by more developers.

--- end quote ---


Yeah, Shadow DOM was definitely introduced as an immature technology with lots of problems. Nowadays there's also Declarative Shadow DOM[1] which allows you to create Shadow DOMs without JS. It alleviates some of these problems at the cost of introducing a few more of its own. It's like a drunken stumble with two steps forward and one back.

[1]: https://developer.chrome.com/docs/css-ui/declarative-shadow-...


More like Dune's sandwalk, many steps aside and little foot rounds for nothing.


Also it ties strong encapsulation with composition (slots) so it prevents easily replacing framework components like React by native components


I think, entangling slots with Shadow DOM was a mistake.

My guess is, most devs just want to use web components with global styles in their page, to make the reusable between frameworks.

However, the moment you want nestable components, you need slots, which are part of the Shadow DOM, which prevents you from using global styles.


I feel like maybe this isn’t well known because it’s the top voted comment and I hear people say this all the time but you absolutely can have global styles with ShadowDOM I do it all the time.

You have two options:

1. you can insert a <link rel=“stylesheet”> tag the same way you might in the <head>

2. Native CSS modules

Example 1: https://developer.chrome.com/docs/css-ui/declarative-shadow-...

Example 2: https://web.dev/articles/css-module-scripts


CSS Module Scripts is only available in Blink-based browsers. It has been accepted by Mozilla and Apple and progressed as a web standard, but it isn’t something you can use today.

Part of the problem with web components is that the component can only style the slotted element and not its descendants. There’s all kinds of weird edge cases that make styling web components painful.

What web developers were asking for was scoped CSS and HTML templates. How it became what it is today I don’t know, but it’s been massively overcomplicated while at the same time having really awkward limitations.


CSS Module scripts are only currently natively supported in blink based browsers because would you believe it Apple is years behind everyone else on web technology yet again for the millionth time.

There is a simple polyfill however in the meantime which means you can actually use it today. https://github.com/guybedford/es-module-shims


Neither Mozilla nor Apple have implemented it; the only rendering engine to do so thus far is Blink. Why are you assigning 100% of the blame to Apple?


Because one of them is a team that is primarily funded by grants but generally tries to do the right thing and the other is the richest company in the world who have a track record over a decade long of actively trying to cripple the web and force everyone into their walled garden.

It shouldn’t be a shock that people might feel very differently about those two organisations based on their previous actions and all.


Mozilla has half a billion in revenue and a billion in cash reserves they seem to want to spend on anything but their browser. Mozilla is no pauper.

When 1/3 rendering engines implement something, that engine is ahead. When 2/3 engines implement something, the other engine is behind. But you are so keen on dunking on Apple, you’re perceiving 1/3 engines implementing something means that just one of the other two engines is behind. That’s an incredibly lopsided way of viewing things.


For what it’s worth it’s actually at 72% support according to Can I Use data and nothing at all like your 1/3 claim and as I mentioned has a polyfill.

I don’t know why it is but almost every time I see your username pop up on HN it’s always bending over backwards to protect Apple from some perceived criticism. People are allowed to talk shit about them, they are going to be ok I promise.


That doesn't tell you how many different engines there are that support it though, only the amount of marketshare covered. Compare it to web-bluetooth (which both Apple and Mozilla have rejected and is hence not a standard): https://caniuse.com/web-bluetooth, which shows 76.24% (as of this post's time). Chromium-based broswers have it, others do not, hence it doesn't really matter what the actual percentage is, only which engines support it (and currently, of the big 3, only 1 does support it).


This information is hard to find. I also used to think it wasn't possible until I did a deep dive into Web Components.

Another way to style elements that are inside the Shadow DOM (from the outside) is to use the `::part(partname)` pseudo-selector, but you need to set the `part="partname"` attribute on elements inside the shadow DOM in order to allow them to be styled from outside with the pseudo-selector.

Another approach I found which is useful when building components which work with slotted template tags is to project the slotted template's content into another slotted element (e.g. a div) provided by the user the from outside. The second slotted element acts as a viewport which holds the component's rendered HTML output. So the component requires the user to provide both a <template slot="item"></template> element and also a <div slot="viewport"></div> element to project the rendered output into. I wrote a post about it:

https://dev.to/jondubois/web-components-the-template-viewpor...


With regard to inserting a <link>, IIRC you can clone the DOM node corresponding to the <link> in the root document to ensure that the CSS isn’t loaded or parsed twice (though no doubt the browser might be smart enough not to do this anyway).


Interesting!

So, I could include Tailwind in all my components and simply use the classes as I do without components?


From components I expect some level of style independence, but I agree it could have been done better.

You can pass css variables, or full link urls to the stylesheets to the inside of the components. If all your components support that, then effectively you can override any style.


Sorry for the tangential question, but do people working in frontend feel that knowledge of the web fundamentals is not present in newer developers? Like the fundamentals of HTML, HTTP, CSS and vanilla JS?

I am no longer very exposed to the frontend landscape but I am curious if those who gained intimate knowledge of those technologies back when it was all that was present might have a niche lucrative role in the future of web tech. I know they are quick to learn, but the idiosyncrasies were always an arcane art.


I've been a full stack developer for a long time and I focused more on the front-end recently. I had to build a large team, so I attended a lot of interviews (a LOT, we are talking three digit numbers, for a remote position with global availability) as an evaluator. There is this very-well-paid 10% top coders who can do everything and do it well, 30% who are very good in their area of expertise but lack quite some general knowledge, 40% who can do things with a very specific choice of technologies and tools, and the rest 20% are clueless enough to give answers like "I can't solve fizzbuzz as I'm not a backend developer" (quote from an actual interview).

I'm not sure how it compares to the backend world, but here everybody is fighting to hire the top 10%, while the lower tiers keep applying to many positions to get hired eventually.

Obviously throwaway acc to not break any hearts.


I recently saw a blog post from a front end dev who was completely amazed about finding out that you can send an HTML form without JS, followed by equally amazed comments. So, yes.


Just wait 'til they find out about <meta refresh>


Judging by people who make links via click listener on DIV, the answer is no.

On one side it’s understandable that people work more on abstractions and are more productive (e.g. learn React first, then maybe understand how P is different from DIV), on the other side it’s incredibly frustrating to see links that aren’t real links even on Google’s websites.


> people work more on abstractions and are more productive

Well, that's one way to define "productive". If a site contains links that are "clickable divs" or has layout shifts, or whatever other "modern" atrocity, can the work really be rated as "done"?

Without done work, productivity is either zero, or undefined.


> Judging by people who make links via click listener on DIV, the answer is no.

Backend dev that dabbles in front end here. What’s the problem with this?


It's reinventing what browsers can already do if you use an HTML link <a href="…"> so it's inefficient. It's also inaccessible.

* It's not in the focus order so you can't keyboard navigate to it. You have to add tabindex="0" to the div to correct that. * It's not keyboard operable. You have to add not just a click listener but also a key press event listener and check that the key pressed is Enter. * It has no role so a screen reader user doesn't know that it's a link. You have to add role="link" to it.

It's also missing useful user experience features of actual links

* You can hover a cursor over a real link to see the destination URL in the status bar. * You can copy a real link's URL. * You can use alternate clicks or a contextual menu to open a link destination in a new window.

Search engines can't find and index the destination of fake links.


HTML means HyperText Markup Language. HyperText means “documents linked to each other”. By not using <A> you’re skipping the core reason why HTML exists, as defined by its name.

The other comment explains pretty well what that causes in the browser.


From the point of view of somebody who has been writing front-end code on and off from the late 90s through to present day:

There isn’t much understanding of the architecture of the web these days.

People commonly think of web development as a combination of two things: a browser environment in which their JavaScript application runs, and a backend that can provide an API for it to use.

HTML is seen as something that is constructed by JavaScript in the browser. HTTP is just the way you get JSON from the API. URLs are unimportant beyond the desire to make what appears in the browser’s location bar look nice. There’s little understanding of how hypertext is supposed to work.

Tailwind is popular for CSS. People construct their layouts and styles by adding numerous very finely-grained classes to every element in a way that resembles inline styles. There’s very little understanding of how to organise CSS – the most common argument I hear for Tailwind is that it’s impossible to keep CSS organised without it, as if the alternative is to just write one big stylesheet with everything in a mess. “Coming up with names for classes is hard” is something I’ve heard loads.

Graceful degradation / progressive enhancement is now niche. Unobtrusive JavaScript is pretty dead. Fortunately, server-side rendering is making a comeback, but unfortunately most of it relies upon running front-end things on the server with JavaScript as a speedup to bootstrapping the JavaScript running in the browser.

Front-end code is now written in the context of front-end JavaScript frameworks instead of what the browser natively provides. Browsers natively support web components these days, but they were devised by architecture astronauts and are not pleasant or easy to use. Instead people write components with React, Vue, Lit, etc., which have varying degrees of interoperability with web components, which very few people care about. If you want to use a third-party component, you look for one that is written specifically for your framework.

The web platform itself has come a long way though. Browsers almost completely agree on how to render things; CSS layouts are a lot easier and more capable; you don’t need CSS hacks to target workarounds for specific browsers any more; people upgrade their browsers frequently; and even when there are backwards compatibility issues, there are a lot of tools that will transcode it to more compatible older code at build time or polyfill at run time.

If you’re an old-school web developer, you’d probably enjoy writing code with all of the new options available to you. But you’ll probably be quite frustrated when working with newer developers who view the web more like a deployment target for an executable than a real platform with unique strengths.


> There’s very little understanding of how to organise CSS

Was there ever? It seems everyone thinks they have the best way to organize CSS. But it's always just a system that makes sense to them and only them. I'm not convinced there's some enlightened way to organize CSS


There are multiple way of organising CSS effectively that aren’t specific to single organisations. But my point wasn’t that there is an “enlightened method” that will solve all of your problems, I was pointing out the common misconception that there are only two options: organised CSS with Tailwind or a chaotic free-for-all.


I think css must be the worst invention in computing, at least all the obfuscated javascript i know is trying to do something (spy on me), instead css just bloats up 800ms on linkedin into the size of war and peace because of how much they throw their weird 6 character psuedohashes in (WHY)


A bloated linked in has nothing to do with css, but with the company behind it. Everything Microsoft touches is bloated, slow, complex, but somewhat functional enough that common people use it. Tech people hate it in most cases.


ITCSS and css modules are (or were?) both popular and help quite a bit.


You should turn this comment into a blog post.


I am not sure this is related to being a newer developer, the thing is that sources of truth regarding frontend languages are not obvious to find, contrary to say the official Golang tutorial I am amazed at the quality of the Mozilla Developer documentation though it's a good place to learn


After reading the article, I was more confused than before.

The 'shadow' DOM is a 'hidden' space? But it is displayed to the user!

And what about this?

> Use case and examples: 2. The <video> HTML element where there’re default controls exposed by the browser. We see just a video element in the DOM, but it contains buttons and some other stuff inside its Shadow DOM.

Why do we use Shadow DOM for this? It sounds like something HTML and CSS can do just fine.


Sure but if you make a video tag, it’s nice that the controls are just there, without having to code them yourself.

Shadow DOM is how browser vendors implemented that. They could’ve also said “this is internal magic” but instead they made it a standard so other people can use it too.


I still don't really understand the regular DOM and what has happened to web development since the good old days of geocities..

Why does everyone need a full operating-system tier browser to render any website with javascript?


I mean the good news is that the regular DOM never really changed. It's still as awkward and clunky as it's always been. And all the snazzy new features that aren't just "here's an API for (other thing)" are pretty much universally trying to make using the DOM less painful.

Async/Promises/Awaitables -> Callback Hell.

Shadow DOM -> Not being able to defer DOM changes.


Tying slots to shadow DOM was a huge mistake. There are better solutions for style encapsulation. Sadly a lousy standard that holds web components back.


I don't want to be that old man yelling "oh, in my days!!!", but honestly, a lot, if not most, of the web "innovations" seem to make things considerably worse, and shadow DOM is a great example of this.

For instance, I used to be able to style archive.org old site and implement a dark mode, but then they had the brilliant idea of starting to use shadow DOM and for some reason extensions like stylus/dark reader simply don't work on shadow DOM yet, you can't change those elements, so dark mode does't work. And all for what? The funny part is that the old site front-end was just okay, no problem, it just worked.

Honestly, I just don't get why web developers – especially the ones in internet archive foundation, which really should focus on things such as accessibility – keep changing things that simply didn't need to be change.


The use case seems to be very obviously isolation (archived site can’t affect archive.org’s header), although I think iframes would have been a much better solution to this)


Here's an example: https://archive.org/search?query=bach

It's on the search archive collections. All that "collection-browser" tag is inside a shadow-root. It didn't used to be like that.


There was a missed opportunity in not naming the article "Shedding Light on the Shadow DOM".


One of the unexpected use of shadow DOMs for me was a document generated for image resource URLs [1], because the HTML standard apparently specifies the exact DOM structure of the generated document except for the `<head>` element [2].

[1] https://github.com/chromium/chromium/blob/f02ca734bf0/third_...

[2] https://html.spec.whatwg.org/multipage/document-lifecycle.ht...


The first link is broken, can you please fix it, thanks!


Oh, thank you for pointing that out! I shortened the commit hash to 7 letters (as I often did) but that was not enough to disambiguate them, a new link should work.


I fairly recently used Shadow DOM for a project. We built a widget that was embedded in a web page, and that page could be arbitrarily styled. The outside page was typically a Wordpress theme, which in most cases did all kind of nasty things with CSS.

Even though there is CSS encapsulation, styles can still leak (cascade?) from the parent element into the Shadow DOM. You therefore need to put a style tag on the root that resets all styles.

Even then, there are some things like CSS transformations that will still affect elements within a Shadow DOM.

Another weirdness is that React modals are usually going to break unless you pass them a reference to the Shadow Root. Most popular libraries have been modified to take such a reference.


Yes but it doesn't leak CSS when you want it to, I've never figured how to setup a CSS only dark theme using a top-level classname like Tailwind does for instance


CSS custom properties are what you’re looking for here.

They cascade into the ShadowDOM without any issues.


If you want classnames:

- <my-component class="dark"

- :host(.dark) to style inside the component




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: