This content originally appeared on Go Make Things and was authored by Go Make Things
I often say that the Shadow DOM is an antipattern. I tend to catch a lot of shit for it, because for years the JS framework cult positioned the Shadow DOM as the killer feature of Web Components.
But one of the biggest challenges the Shadow DOM creates for Web Components is around styling.
It breaks the cascade, and makes styling things a million times harder and more repetitive than it should be. Today, we’re going to look at why it sucks, and what our options are.
Let’s dig in!
The Shadow DOM breaks the cascade
The Cascade (the first C in CSS) is one of CSS’s most powerful features. It lets you write way less CSS while providing a consistent look-and-feel throughout your site or app.
Imagine a world where you needed to specify the font-family
individually for every single element in your UI…
a,
p,
strong,
em,
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'PT Serif', sans-serif;
}
Instead, you can do this…
body {
font-family: 'PT Serif', sans-serif;
}
Thank you, Cascading Style Sheets!
But because the Shadow DOM is encapsulated from the main DOM, the styles in your global stylesheet do not cascade into it.
An example
Imagine you’ve got some HTML that looks like this…
<style>
button {
background-color: rebeccapurple;
border: 0;
border-radius: 0.25em;
color: white;
font-family: 'PT Serif', sans-serif;
font-size: 1.2em;
padding: 0.25em 0.5em;
}
</style>
<count-up></count-up>
And your <count-up>
Web Component looks like this…
// JavaScript
customElements.define('count-up', class extends HTMLElement {
/**
* The class constructor object
*/
constructor () {
// Gives element access to the parent class properties
super();
// Component properties
this.count = 0;
// Create a shadow root
this.root = this.attachShadow({mode: 'closed'});
// Inject the HTML into the shadow DOM
this.root.innerHTML = `<button>Clicked ${this.count} Times</button>`;
// Listen for events
// ...
}
});
When it runs, the rendered HTML will looks like this…
<count-up>
#shadow-root (closed)
<button>Clicked 0 Times</button>
</count-up>
And the <button>
will be styled with… the default browser styles. None of your colors, fonts, or sizing will cascade into it.
How to style Web Components in the Shadow DOM
There are five different ways to address this. They all kind of suck.
- Inline CSS. Hard-code styles with a
<style>
element inside the Web Component. - CSS Variables. While global CSS doesn’t cascade, CSS variables (or custom properties) do, and can provide hooks for developers. to style things.
- Web Component Parts. An API for styling specific parts of the Shadow DOM.
- @import. An easy but sub-optimal way to load your global stylesheet in the Shadow DOM for your Web Component.
- Constructable Stylesheets. An API for sharing styles across components. Browser support isn’t great.
Over the next few days, we’ll look at each of these approaches in a bit more detail.
Why this all sucks
Having a global design system kicks ass.
You can load your CSS into the page, and all of your UI will pick up the styles and look cohesive.
This is true even if you manage a third-party script that loads into someone else’s UI.
If a script I wrote adds a button to someone else’s UI, I want that button to look like their UI elements and brand, not my predefined ideas of what it should look like.
This content originally appeared on Go Make Things and was authored by Go Make Things
Go Make Things | Sciencx (2024-11-04T14:30:00+00:00) Styling the Shadow DOM with Web Components. Retrieved from https://www.scien.cx/2024/11/04/styling-the-shadow-dom-with-web-components/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.