Is JavaScript a dependency?

posted on

Back to overview

It depends.

Let’s say you have a message component that has a different styling based on its type (info, warning, or alert). If you pass the body of the message through an attribute to the component, similar to what we did with the Star Wars component earlier, and you use JavaScript to render the message, then JavaScript is a dependency.

<the-message type="warning" text="That's a warning"></the-message>

You don’t have to do that, though. You can also pass content to the component by putting it between the start and end tags. That process is called slotting. The big advantage here is that content now lives in the document, as well.

Light DOM

If JavaScript doesn’t work, the text between the start and end tags will still be displayed because it’s part of the light DOM. Since the JavaScript code in the component doesn’t run, the component functions differently, and it might also look different, but the content is there!

<the-message type="info">
That's an info

That's an info

For me, someone who believes in progressive enhancement and that websites should work without JavaScript, that’s great news.

JS only

If the component content needs JavaScript to run in the first place, you don’t have to bother with the light DOM. If you create a map component, for example, you don’t have to pass the entire iframe to the web component because the entire thing relies on JavaScript. You could pass coordinates, and the web component renders the map and embeds third-party styles and scripts. In such a component, it makes sense to use shadow DOM to ensure that styles from the outside don’t interfere with component styles.

<the-map lat="48.188009691340454" long="16.412904197976452"></the-map>

Declarative Shadow DOM

A limitation of the shadow DOM is that it's rendered on the client entirely. Declarative Shadow DOM removes this limitation, bringing Shadow DOM to the server.

A Declarative Shadow Root is a <template> element with a shadowrootmode attribute. The HTML parser detects the template and applies it immediately as the shadow root of its parent element. This means that it's possible for a Custom Element to have a shadow root before it gets upgraded. You don't need JavaScript to attach a shadow subtree to the element.

<the-message type="warning">
<template shadowrootmode="open">
:host {
--_border: blue;

display: block;
border: 4px solid var(--_border);
padding: 0.5em;

:host([type="warning"]) {
--_border: orange;


<p>That's a warning</p>

You still want to upgrade your component so that you can make proper use of it.

class TheMessage extends HTMLElement {
static observedAttributes = ["type", "text"];

constructor() {

customElements.define("the-message", TheMessage);

That's a warning

That's pretty cool, right? So, what's the catch? Firefox doesn't support Declarative Shadow DOM.

Disable JavaScript in your browser to see how it affects each component.

Back to overview