The Web Components Revolution

Introduction
Scott Jehl begins by setting the stage for his talk on why web components, while helpful, can't single-handedly solve the web's performance and accessibility challenges.
Performance Problems in 2024
Scott discusses the persistent performance issues plaguing the web despite advancements like 5G and evergreen browsers. He emphasizes the uneven distribution of these advancements, with many users still relying on low-end devices and slower networks.
The Mobile Divide
Scott explains how the disparity in mobile device performance contributes to the uneven web experience. He uses a chart to illustrate the performance gap between high-end and budget Android devices.
Network Disparities
Scott shifts focus to the role of network speeds in the varying user experience, noting the limited reach of 5G, especially in rural areas. He humorously digresses with a theory about cell phone companies' obsession with making networks look like trees.
The Developer Perspective
Scott addresses how developers, often having access to high-end devices and fast connections, can have a skewed perception of website performance for the average user.
The Rise of JavaScript and Its Impact
Scott divides the history of web performance into two phases. He explains how the improvement in browsing conditions in the 2010s, instead of solving performance problems, led to an over-reliance on JavaScript and the rise of client-side rendering, creating new performance bottlenecks.
Client-Side Rendering vs. Server-Side Rendering
Scott demonstrates the performance difference between client-side and server-side rendering using a video comparing the loading times of a React website on high-end and low-end Android devices.
The Benefits of Delivering HTML
Scott advocates for serving HTML directly from the server to leverage browser optimizations, citing a webpage test experiment showcasing the performance improvement achieved by serving pre-rendered HTML.
The Rise of Server-Side Rendering (SSR)
Scott discusses the positive trend of frameworks like Next.js adopting server-side rendering, which helps move JavaScript out of the critical rendering path.
Performance Measurement Tools
Scott highlights performance measurement tools like Speedcurve, Calibre, debug bear, web page test, and CrUX (Chrome User Experience Report) and explains how these tools provide valuable insights into real-world website performance.
Core Web Vitals and SSR Performance
Scott analyzes the performance of server-rendered framework sites based on Core Web Vitals metrics, pointing out the issue of high JavaScript payloads despite server-side rendering.
Perceived Performance and Accessibility
Scott challenges the notion of perceived performance, particularly for users relying on screen readers, illustrating with examples how blocked main threads can negatively impact screen reader users even with early renders.
The Case for Web Components
Scott introduces web components and their potential to improve web development practices, emphasizing that they are not a silver bullet but rather a step towards a more resilient and performant web.
Web Component Adoption
Scott showcases the growing adoption of web components by companies like Adobe, Apple, SpaceX, Microsoft, and GitHub, demonstrating their real-world applicability and robustness.
Web Component Fundamentals
Scott explains the core concepts of web components: custom elements, HTML templates, Shadow DOM, and slots, detailing their functionalities and how they work together.
HTML Templates
Scott discusses HTML templates, clarifying their limitations compared to framework templating systems and suggesting alternative templating approaches for web components.
Shadow DOM and Slots
Scott dives into Shadow DOM, explaining its purpose, how it works, and the implications for CSS, JavaScript, and accessibility. He also discusses slots, highlighting their role in composing content within the Shadow DOM.
CSS and Shadow DOM
Scott touches on the complexities of CSS within Shadow DOM, encouraging developers to explore the topic further to gain a deeper understanding of CSS in general.
Accessibility Considerations with Shadow DOM
Scott points out the accessibility challenges presented by Shadow DOM, particularly with forms and validation, and suggests workarounds for these issues.
HTML Web Components and Progressive Enhancement
Scott advocates for using web components as wrappers for functional HTML, promoting progressive enhancement as a key principle in web component development.
Exploring Native HTML Features
Scott urges developers to exhaust native HTML features before resorting to JavaScript or web components, highlighting new and upcoming HTML capabilities like popovers, CSS anchors, stylable select elements, view transitions, and responsive video.
Combining HTML and CSS for Powerful Results
Scott shares his experiment of rebuilding Wordle without JavaScript, showcasing the potential of combining HTML and CSS to achieve complex functionalities.
Rethinking Web Development Practices
Scott reiterates the need to rethink web development patterns and move away from JavaScript over-reliance, emphasizing the importance of embracing new standards and approaching web components strategically.
Integrating Web Components with Frameworks
Scott discusses strategies for integrating web components with existing framework-based projects and suggests tools like Enhance.dev, webc, and lit for building and composing web components.
The Future of Web Components
Scott concludes by highlighting upcoming web component features like declarative custom elements, DOM parts, and signals, emphasizing their potential to further enhance web component development and reduce JavaScript dependencies.
Conclusion
Scott summarizes the key takeaways of his talk, emphasizing the need for a shift in web development practices towards more resilient and performant websites through strategic use of web components and native web standards.
Things have changed.
I'm gonna be talking about making sausage, apparently.
Which is strange, I'm a vegetarian.
But, we'll work with it.
No.
I am here to explain why web components can't save us.
Not by themselves, anyway.
Maybe you're thinking, save us from what?
To answer that, first, I'll talk a little bit about performance and accessibility problems.
So why do we still have performance problems in 2024?
I think it's a valid question, right?
Isn't everything good now?
We have 5G, we have evergreen browsers, AI that's at least as trustworthy as a stranger on a street It's true that for many of us things are pretty good right now, but to borrow a quote, while the future is here, it's not very evenly distributed, right?
So the way people experience the web is highly dependent on their circumstances.
Why is that?
Part of it is due to our mobile devices.
So this chart, I'm sorry for the chart, I won't show many charts.
This chart shows, performance benchmarks between popular mobile devices in the last decade and 10 years ago all the devices were similar in performance, but that's changed a lot.
The performance of high end devices like the iPhone 15 it's very different from a budget or a low end Android these days.
It's almost five times faster now at churning through the code that we deliver it.
Networks play a small part or a large part depending on the, user in that disparity of, experience as well.
Like devices, networks are getting faster too.
But again, unevenly.
5G, the rollout has continued, but 5G still doesn't, reach into much of the rural world.
It's taking a long time, I think, to build faster networks that work for everyone.
And I'm not really sure why that is.
I'm sure there are a lot of reasons.
One theory I have is that they spend so much time making our networks look like trees.
And don't get me wrong, I'm impressed by what, that's pretty believable.
If I didn't know what coconuts look like, that's pretty good.
It just seems like this is a really high priority for the cell phone people.
Are cactuses trees?
Cactuses are trees.
Thanks for hearing that theory.
So the networks have been generally getting better.
5g is spreading, but even in areas with 5g service people with older and budget devices often can't enjoy it because their phone lacks the hardware to connect to it, right?
So they're stuck on slow phones and slow connections.
And that's only made worse because these problems are not always very visible to the people who are actually building the websites that these people use right so on the whole web developers like us tend to have access to pretty fast devices and connections, right?
Especially while we're working and experiencing our own websites, under those ideal conditions every day can give us a skewed perspective of how they behave for our actual users.
With this chart, I have carelessly reduced the history of web performance challenges into two phases.
In the early days of the web, it was hard to make fast websites because the medium was, not fast, right?
Devices weren't fast.
Networks weren't fast.
The constraints were really hard.
Sometime in the 2010s Things started to change a bit.
Browsing conditions were getting better.
Networks were improving.
And a lot of us started to experience the web with fewer constraints, right?
And let's be clear, like, when that started happening, those improvements should have naturally fixed a lot of the performance problems that came before that point.
That's not really what happened.
What happened was, instead, we saw Moore's Law as an opportunity to add more JavaScript, right?
And we began to really rely on that JavaScript, for our delivery of content.
Credit to Andy Bell, a friend of ours, for that meme.
I won't show many memes, but I love that one.
React was released around this time.
And even though React was meant for building massively multiplayer real time UIs, like Facebook, people just started building everything with it.
Blogs, every website.
So right as networks were starting to improve enough to alleviate performance problems.
We made new ones popular practices moved away from delivering meaningful HTML from the server and instead generated it after delivery and in doing so we shifted the performance burden from the networks to the devices This pattern is still very common today, so let's look how it plays out.
I'm gonna play a video of the same client rendered React website loading in, two different Android devices, one high end, one low end.
On the left, it's gonna be the high end device.
On the right, low end device.
This is a live website, by the way.
Let's just hit go on that.
So again, same connection speed, same browser.
Modern Chrome.
That one's done.
That's a Galaxy 23 on the left.
And on the right, the budget Android, which you can still buy in a store.
There we go.
So that's still on a 4g connection, right?
So when we offload our compute.
To different computers it varies, quite a bit, right?
Maybe you think, that's just a slow device, right?
But here's the thing, low end devices can still render websites quickly.
We just need to deliver websites the way browsers are designed to receive them, right?
As HTML.
This is a webpage test experiment that I ran, to do just that.
We're taking a site that's rendered on the client, and again, I'm showing real sites, but this is more about the practices.
This is very common.
That's Airbnb.
Lots of sites do this, right?
The one on the left, finished loading in six seconds.
It was an experiment that mimicked serving the HTML from the, the final state from the server instead.
Critical optimizations, are, happening in the browser when we deliver HTML up front.
For example, those images.
They start to get fetched before the DOM is even created, right?
The browser actually looks through the raw HTML and gets to work.
If we generate HTML after delivery, we completely forfeit our opportunity to even take advantage of optimizations like that.
It's taken a long time for frameworks to help us out of this dilemma, especially if we're tied to a framework already, right?
But things have gotten better.
In the last couple of years server rendering of framework sites like React and others, is now something that companies are touting as a feature.
And that's awesome, right?
So Next.JS is one of those.
It renders React sites on the server side.
This is a really good trend, right?
So for framework sites, it's becoming easier to get JS below, at least out of the critical delivery path, right?
It's not necessarily out of the way entirely.
I'll get to that in a second.
But at least it's not in the way of the HTML.
So that's very good.
So we have some tools that we can use to measure how this is working these days.
Tools like Speedcurve, Calibre, debug bear, web page test.
I worked on that tool for a couple years.
These are really good tools.
Some give us information about how people are actually using our site, like CrUX, which stands for, Chrome User Experience Report, which, I don't want to dwell on this, but that's not how acronyms are supposed to work.
Crux is interesting.
It services data that's collected from Chrome, like all of us using Chrome, anonymously.
And you can opt out of that.
It collects a lot of data, and you can see site by site how people are actually experiencing, sites by domain on mobile and desktop.
So I'd recommend checking it out.
What do these tools tell us, right?
The performance community has standardized on a bunch of metrics.
These are a few of them.
You might recognize them as Core Web Vitals.
That's what Google calls them.
And they give us, key insights into different, delivery and, post delivery moments, right?
So LCP is for, the paint.
Like, how soon does the page start to visibly appear, right?
CLS is about shifts.
Is it janky as it comes in?
Mandy talked a little bit about that.
Images push content around, right?
INP is about, latency after interactions.
So if JavaScript's involved in that, latency can increase quite a bit.
So how are server rendered framework sites doing on these metrics?
I tested that recently.
So this is one test that I ran in a very fast Android device.
Galaxy 23, S23.
Yeah.
So like a, middle of the road actually.
But pretty good Android device.
Fast connection, 4G, Chrome browser.
And you can start to see that look at this, 2 seconds we're seeing, the page start to render.
That's great.
That's the beauty of serving HTML, right?
So LCP says 2 seconds.
Of course, there is a, metric here that's a little problematic.
Even on a fast device.
1. 8 seconds of total blocking time.
That means that the, the main thread of the browser was, jammed up.
It won't respond to user interaction, for almost a couple of seconds here.
So that's problematic.
It's not like a huge delay, but on a fast device, it's interesting to look into, so what's causing it.
That site, shipped four megabytes total of code.
But of that, we can look at the breakdown and see that.
Most of it was JavaScript, right?
So it's server rendering HTML, but there's still, three megabytes of JavaScript, which unpacks to 11 in memory.
It's a lot for any device to handle, even a fast one.
And this is the common problem we're seeing with a lot of server rendered React sites today.
They're still shipping a ton of code, for rehydrating the page after delivery, right?
And just to be clear, this is a popular website, but I see payloads much heavier than that these days, so the problem is, is, out there.
What about on a low end device?
Once again, this is a low end Android.
LCP is still pretty good, so it's painting in three seconds.
On 4G, that's not bad.
But look at the blocking time.
We're at 20 seconds on a low end Android.
When I talk about something could save us from something, this is the sort of thing I think we'd want to be saved from.
Here's another way that it impacts people that I think is pretty interesting.
In general, it's good to render a page before it's usable.
It's this idea of perceived performance, right?
Most people agree on that.
But it's not everyone's experience that an early render is actually perceivable.
So it turns out that some of the performance metrics that we've standardized on are not, totally inclusive.
So what does an early paint mean of content, to someone who's listening to the page?
[screenreader voice] Welcome to Scott's website.
I'm going to replay that.
I'm doing a little test.
This is just a basic HTML page with an H1 in it.
No JavaScript running or anything.
Voiceover's running and what happens is I open the page in the browser and as soon as it can, it'll proceed and read that H1.
So I'll play it again.
[screenreader] Chrome, welcome to Scott's website.
No surprises, no problems.
That's how it should work.
I'm going to do a second test.
And, it's the same page except this time I added one deferred JavaScript file.
And, deferred makes it load after the, the content can appear, right?
And then the script runs and it applies to the page.
So it kind of mimics that, that scenario of like server rendering plus Rehydration.
In that script I wrote a little while loop that would just jam up the main thread for six seconds.
Okay.
So let's see what that does with a screen reader.
[screenreader] Chrome Scott's website, Google Chrome, Scott window, Scott's website, selected tab group.
You are currently on a selected tab group inside of a group to exit this group.
Press Scott's website.
Welcome to Scott's website.
Okay, so what you heard there was voiceover just like awkwardly filling the time and just being like we're still looking at a tab here it's Scott's website and, yeah, so like the main thread was blocked.
We had an early render So like sighted users got a nice little optimized experience start to read the page If you're on a screen reader, like that 20 second delay that we saw on a low end device, it would just be silent, right?
Or at least repeating the tab name.
So you don't have a lot of context into what's going on.
I think more inclusive metrics can help.
We don't have them yet.
This is a issue that I filed with the Lighthouse team.
Some folks in the accessibility community have plus one'd it.
If you would like to do the same, that'd be great.
I think it could use some more attention.
So those are some real problems people are facing.
Even with Cutting edge practices, right?
It's clear that not only we need to, move to serving HTML again, but we also need to reduce the amount of JavaScript that we're delivering.
So why am I here to talk about Web Components, right?
Two reasons.
First, John Allsopp asked me to.
And, the second reason is that I think web components offer us an opportunity to evolve our practices.
They're not going to fix everything on their own.
But I think they're, they reflect, maybe a way forward.
So maybe you've tuned out on them, in the past several years, and if you have, totally fair, it was a little rocky early on, I think things are a little better now, lots of big companies have adopted web components recently, so Adobe, for example, has standardized them, they have a open source web component library called Spectrum, it drives a lot of their flagship products on the web.
And when I say that, I should be clear, like, when Adobe has, standardized on web components, they built Photoshop on it, right?
These are battle proven, technology at this point.
The real Photoshop, right?
This is, me, using the latest version of Photoshop, which runs in the browser.
It works just like you'd expect Photoshop to work.
As you can see, graphic design is my passion.
In the browser, if you just pop into DevTools, you can see all these little weird elements that you know, those aren't, right?
That's psw-app-context, right?
So those are web components.
They have built, a lot of their apps on, these tools now.
So they're all in.
Apple is another one.
The Apple Pay button, if you've ever used it, put an Apple Pay button on your site.
It's a web component.
So you can see that right in their docs there.
Another one, SpaceX.
Maybe you were thinking, web components sound pretty good, but surely they don't work in space.
Guess what haters?
They work in space!
The UI of the Crew Dragon, spaceship runs on Web Components.
So you can add space to your browser support matrix.
Microsoft recently just rebuilt Edge browser, like the actual browser Chrome in Web Components.
Used to be built in React.
They rebuilt it.
They've reported a lot of performance gains from that.
GitHub's another one.
If you've ever seen these little timestamps that have relative time in the, commits, in GitHub, those are, web components.
Little relative time, you can see it down there.
It's cool.
Takes a timestamp, makes it like three minutes ago, one month ago, whatever.
Another one, Wordle.
It was originally built on Web Components.
So that's pretty cool.
Alright, let's talk about what they are.
First thing to know is that they aren't any one thing.
They're a group of standards that, can be used alone or together.
So those are custom elements, HTML templates, Shadow DOM, and slots.
They all have great browser support now.
I'll start by talking about custom elements a little bit.
They're the best part, I think.
So here's a my element And if HTML, there's no standard built in element called my element.
And that's because I just made it up, right?
That's the whole point of custom elements.
They're real elements that you just make up, the way to know if an element is a custom element, is that it's going to have at least one of those dashes in the name.
So they're, like, little imposter elements made out of dash separated characters, like little squirrels in a trench coat pretending to be HTML.
In fact.
Thanks to flexible naming, rules, custom elements, can use Unicode.
This is completely valid markup.
Actually, let me localize this real quick.
There we go.
I heard we don't have squirrels here, at least natively, yeah, so Unicode is allowed.
There's some rules around formatting.
One of them is that they have to start with an X. Or, sorry, a letter, not an X specifically.
So you see that X in there.
It's gotta be a letter or more, letters and a dash.
There are some other rules.
Again, have to start with a letter, have a dash.
They don't have to have anything after the dash.
So you could end like a dash is, totally valid.
You can have some other types of characters in there.
Like semantic versioning, you could do something like that.
I don't know.
I don't think it's a good idea, but I just put it in there for fun.
They also need to be closed.
You can't have a void element like, like an image, that self closes.
How do we use these things?
Again, they're real HTML, so you can just drop them in alongside Other HTML elements, right?
Like your P and your ULs and all that.
Or, wrap them around HTML.
This is how I like to use Web Components for what it's worth.
Or custom elements, rather.
And since they're real HTML, you have to follow the rules of HTML.
So some elements have rules about what they can contain, right?
Like a UL, is supposed to have LI elements as its direct, child nodes.
So that is not going to work.
You'd have to put it inside the LI.
And this trips some people up, I think, especially if they're coming from frameworks where the concept of a component is almost like a replaced, you don't see the tag name in the end.
It's replaced by whatever it includes.
That's not the case with these custom elements.
Are real HTML elements.
You're really building HTML.
So it's a little different.
So you drop it into the page.
What can you do next?
At that point, it's like a div or a span.
Like maybe that's useful.
We use divs and spans, right?
But it's not interesting yet from an accessibility standpoint or to the user or anything.
Maybe that's all you need.
You could style it, whatever.
But we can take it further by using the life cycle.
So this is something that's specific to custom elements in Web Components.
And the life cycle gives us key moments in that, element's life to, tap into and apply scripting.
To gain access to the lifecycle, we need to teach the browser, about the element name, and register it.
Here I'm doing that.
Custom elements define, pass the, the element name in there, and then here I'm saying, how I'm going to define that element with a class that extends this other class.
I'm going to unpack that a little bit.
So that HTML element class is what gives all elements their default properties like offsetTop or innerHTML or whatever, right?
And our custom element already has all that.
We don't have to add that with script, right?
You just put it in the page.
It's an HTML element already, but if we want to add more behavior and customize it, we have to extend that class.
So that's what we're doing here.
And inside the curly braces, that's where we're going to put our extension behavior.
I'll get to that in a sec. It doesn't have to be anonymous like that.
I could name it like a, as a variable.
And then I could pass that variable in down here.
And this is really popular compared to the first way I showed you, because it has the benefit of being able to export it, importing and exporting modules.
This is how you could like compose components out of other components and, if you want to do that sort of thing.
You don't have to, but here's how you'd import that one if you did want to do that.
So whether you export it or not, you can pull the script into a page with a script tag, right?
This is a really common way to use a web component.
So I've got the custom element, then I've got a module, external file, and it's pulled into my page.
Neat, doesn't do anything yet.
This is our setup, right?
So inside the curly braces.
This is where we start to define our behavior.
The life cycle has a number of callbacks we can use constructor, connectedCallback, etc.
I'm going to cover a couple.
The first, connectedCallback.
Remember when we used to like, add a listener to wait for the whole DOM to be ready, and then once it was, we could apply some behavior to our elements?
We don't have to do that anymore, especially with, custom elements.
connectedCallback is like, DOM ready, but much better.
So with this, you're setting up a callback that will happen anytime the custom element, of that name is found in the DOM.
Which might happen, at page load or it could happen when it's appended to the DOM later.
Really handy.
And at that moment, you probably would do more than console log a message.
You might add some behavior.
Maybe, event listeners on buttons or whatever.
Whatever it's supposed to do.
Also, attributes.
Custom elements can use attributes.
And unlike standard HTML, they can use custom attributes.
So you can just make them up.
Like here, I have greeting equals hi.
There's no standard greeting attribute.
I just made it up.
What's interesting is you can listen for changes on attributes, and that's how people start to build reactivity into their web components a little bit, right?
So you can see that here we have the attributeChanged callback, and it just gives you the new value and the old value, and you can do what you will with it.
One thing about attributes, if you're coming from the framework world, attributes are strings in HTML, so it's good to remind yourself of that.
We're not passing in, data structures here, right?
Just strings I checking out some other lifecycle moments, but I'm going to move on to other ingredients.
The second one, HTML templates.
These give us a way to, statically deliver reusable HTML, essentially.
If you're coming to Web Components from a framework, Please lower your expectations.
These are not what you are probably hoping they do.
But I'll show you what they do real quick.
They just hold arbitrary HTML that's not rendered to the user.
So you can use it later.
I could, build a list by cloning that LI and surgically updating the DOM over and over and it's quite efficient.
But it's not templating in the sense that like you have inlaid variables and things like that you'd expect from like a render function in a framework.
So we'll move on from those.
There are better ways to template.
A lot of, little micro libraries extend the base of, of HTML custom elements to have a little render function that you can pass in variables.
So like you would in JSX or something like that.
But it's not built in.
Alright, the next part, Shadow DOM and slots are, they come along with that.
So Shadow DOM is a relatively new thing to web developers, but browsers have actually been at least conceptually using it for a long time.
And now literally using it as well.
So if, you're in Chrome DevTools, you can check that little box, to show user agent shadow DOM.
And then if you do, and you browse around in your, DOM node view, you'll start to see little shadow roots show up here and there.
So this is a select element, for example.
And you can see, the first child in there is a shadow root, so that's Shadow DOM.
This is just a built in element.
A lot of form components use this, in browsers today.
Web developers can use it too, of course.
Why would you want to do that?
I'm going to say that most of the time, I don't.
It's not a great default for Web Components.
Using it complicates a lot of things.
So it's once you get into the Shadow DOM world, suddenly you own a lot more responsibility.
And it's not like it's buggy.
It's just, you have to know more about what you're doing, right?
It's a lot of things.
If you want to build a custom menu instead of using the built in one, like Select Menu, for example, you have to know a lot about doing all the accessibility behaviors and the keyboard handling and everything.
Shadow DOM is complicated in that same way.
But it's useful in a lot of ways, too.
For example, third party embeds.
Like a, a video player or a chat widget.
A good example is that Apple Pay button.
Sorry, the contrast is a little low here, but this is their configurator tool.
And I'm actually changing settings.
This is in the browser.
There's the button down there changing as I work.
And this is the interior shadow root of that button.
They generate the whole button from JavaScript.
And they do that on purpose because they want to control everything, right?
Anything that's exposed for configuration is on purpose.
And they're not going to let you mess with the Apple logo, right?
So that's not on the table.
But some things are.
What's neat, I think, when you play with that tool, it gives you some CSS output.
And these are CSS custom properties.
Interestingly, those breach through the shadow barrier.
So while a lot of, CSS is encapsulated, so to speak in the, shadow DOM, some things do get through and CSS custom properties are one of those.
And that's a power tool.
You can expose parts of the layout inside the shadow DOM to outside configuration.
You can do that with SVG as well.
So it's, the same thing.
So how do we make Shadow DOM?
I told you about template elements before, and that they're lame.
And that they don't render, right?
That's the default behavior of them.
But we can actually use them to generate Shadow DOM now.
Here's how that looked.
So I, added a shadow root mode of closed.
And, to that template element.
And you can see here that it transformed into a shadow root.
This is called declarative Shadow DOM.
Because I didn't use any JavaScript to create that shadow root.
And that's a relatively new way to create Shadow DOM.
Maybe if you learned about it in 2012 here, you saw something like this.
But this is, an equally valid way to create shadow root nodes as well.
attachShadow.
You would do that in the constructor callback, and then you could set the inner HTML of it.
This is like how the Apple Pay button works, out of, from, afar.
So that's, how you make a root by default, and I showed a closed version.
The encapsulation, with that is so it's really protected from, accidental, collisions in JavaScript.
Down here in the console, I'm querySelectorAll-ing the document for a paragraph, and it's null.
It didn't find anything, right?
So it's encapsulated in that way.
You can actually optionally, make it less so.
If I set the, the mode to open instead of close when I create a shadow root, then you can optionally get into the shadow DOM and then query further.
It's still not something you could do by accident.
The parent of the shadow root gains a shadowRoot property that you can then dig further.
Worth noting, open or closed have no impact on CSS.
So this is just a JavaScript concept about getting into the shadow DOM.
And then, one more thing about shadow root, slots are available to them.
And slots are pretty cool, I think.
It's a way to expose, light DOM, so to speak, like the regular DOM, within the shadow DOM, like in a window.
So see my custom element here?
I've got mirror as the content of that, just a little text node in there.
And that's gonna end up in this slot.
I'll show you, rendered out in the browser, what that looks like.
It's a CodePen view.
So you can see how you might use slots to compose, content alongside boilerplate content.
Like maybe it's a, the area of the header that shows like the username and then you toss the username.
And I don't know, I'm just thinking, there are ways you might use this to compose elements together.
CSS.
If this was an all day workshop, I'm teaching one tomorrow, I would get into how CSS applies to the Shadow DOM.
We don't have the time today.
It's really complicated, actually.
Most CSS doesn't pass through into the Shadow DOM.
But some does, like inheritable properties, color and font size, things like that, will pass through if it's applied to a parent of the custom element.
Conversely, CSS inside the Shadow DOM doesn't get out to the page around it.
That's good.
A couple special selectors do, like you can talk to the host element from inside the Shadow DOM.
Anyway, it's very complicated, but I would actually recommend reading up on how CSS and Shadow DOM work together because you'll learn a lot about CSS just in general.
I know I did anyway.
It's very interesting stuff.
Another thing that Shadow DOM complicates is, accessibility, forms, validation.
Again, all fixable things, but things to be aware of.
So say you have a form input and a label that want to associate with each other.
You always want that.
If one is in a shadow root, They don't know of each other.
So that's a problem, right?
And there are workarounds, but by default, it's a problem.
An input that's inside the shadow root in a form won't submit its value with the form by default.
You gotta work around that.
And there's standards to do that, but again, once you start working with it, just know there'll be dragons or whatever.
Unfortunately, I think what a lot of people think they don't like about Web Components, they actually just don't like about Shadow DOM, right?
And that's because, It's been so popularly used as, the default way to make a web component, over the years.
I would just say, just a reminder, it's optional.
It's one of the pieces.
It's a useful tool if you need it.
So that was a bird's eye view of the three tiers.
I think this native component model that we have built into the browser now could be helpful, with reducing our JavaScript over reliance that has happened over the last decade.
And it's a lot like having a JavaScript framework built into the browser, in some ways, right?
That we don't need to load at all.
And that's like the whole point of a framework, right?
The whole idea is to push practices that end up influencing standards.
I was on the jQuery team for a long time, and that was our stated goal, to make the library obsolete, right?
And they did that through influencing browser standards.
querySelectorAll came from, the sizzle engine thing, where we were running CSS selectors in JavaScript, right?
Now we don't need jQuery anymore, legitimately.
So I think we need to start thinking about Web Components as this may not be my preferred syntax, but this is the standards path to, to keep moving forward.
But we need to change our patterns and our practices to get there.
It's not going to just happen automatically.
One such pattern that's really resonated with me for a while now is something that Jeremy Keith has called HTML web components.
The idea is to just build web components as wrappers for functional, already meaningful HTML.
And then you use the lifecycle to make that HTML a little more interesting do something more than it could do by default.
So progressive enhancement basically, right?
Here's one example of one of those.
It's, it's built by the team at cloud four.
It's called image comparison.
Yeah.
Comparison.
Yeah.
And it.
It does that.
It compares two images.
It's pretty slick, right?
The UI is nice.
Under the hood, this is the source, right?
We have two image elements.
If this script failed to load, we talk about, what if people have JavaScript disabled?
It's more what if that script, something in the network conditions caused it to not load or an error happened in some browser, whatever.
At least we have a couple of images that we can visually compare, right?
So the, markup starting point is nice.
That's my favorite way to use Web Components to extend HTML further.
But backing up, before we start to think about patterns, I think, we need to be exhausting all opportunities to just use features that are built in to HTML today, right?
There are so many ways that we can stop using JavaScript now, and they have nothing to do with web components, right?
So a bunch of new stuff has landed recently.
Zach talked about, Popover.
That's amazing, right?
We have fully stylable little, overlay thingies now, that's just HTML.
It's pretty awesome.
And it's cross browser, right?
That's one potential piece of JavaScript we could remove from our code base.
CSS anchors.
That's like a. Upcoming thing, but pretty exciting.
Who's written collision detection JavaScript before?
It's gross, right?
I don't think I've ever written, bug free collision detection.
This is huge.
It'll really help us solve, some, problems once, once it lands.
It's, it's still coming in a couple of browsers anyway.
Stylable select elements, right?
Your design team is gonna be so happy.
We are about to get the ability to put icons in the, options, right?
The Chrome team has been working on this.
That's coming soon.
This is huge because people rebuild entire selects just to get an icon in there, right?
And it's legitimately a, limitation that teams are working against.
Really exciting to see.
We can transition between pages now using web standards.
Ellie's going to be giving a talk about this.
A huge reason that a lot of people adopt single page app frameworks is just to get this effect, right?
To transition between pages and now it's, built into the browser.
For browsers that don't understand it, I think it's just Firefox.
Is that?
It's complicated.
Yeah.
Yeah.
In those cases, you just get a page that changes, right?
Like without a transition.
It's fine.
People might even prefer that.
View transitions, another example of deleting some JavaScript.
Responsive video, this one's a little near and dear to me.
For local video files, like self hosted for example, you can serve two different sizes or, orientations of a, video.
Just like responsive images, like the, picture element.
I was able to actually land the commits in Firefox to, to get this feature supported in that browser last fall.
It works again now.
It actually used to work, and then it didn't.
And it's a long story, and it's on my blog if you want to read about it.
Heh, few swear words, but maybe a couple.
Just generally, combining HTML and CSS is wildly powerful right now.
Earlier this year I did this experiment on my site to try to rebuild Wordle without using any JavaScript.
And I actually got pretty close.
It's fun to experiment with these ideas and just think about how could we do this?
Forms have a lot of validation attributes and patterns and CSS can tap into those, right?
So a pattern attribute could actually define the acceptable letter for each input and then we could style them accordingly if it's valid or invalid, right?
We could take that even further.
Here's some of the CSS behind it.
It actually validates all of the inputs.
In the row once you fill in each one and get to the end.
So you can't really cheat, and see the answer along the way as you're, going.
And it does that by looking at the table row.
So it's actually built with a table of inputs.
And it's saying if it has an input with a placeholder attribute, or placeholder text shown, or it's still focused, and it's invalid, then make it light gray.
So it's actually like looking at the whole row, at the inputs and making sure that they're all filled in before giving you the answer for that, whole row.
And then in the blog post, it goes a little further to add the tan color because CSS invalid in and valid doesn't really give you that, this answer's right, but it's only right in this input over here, Wordle does.
Yeah.
Sometimes we need a little JavaScript to do things like that.
When I, when I say web components, alone can't save us, this is what I mean, right?
Standards allow us to look at, at problems a different way, but we can't just, npm install our way.
Into that fix, right?
We have to actually rethink things and use these new standards in different ways than we are with frameworks.
So maybe you're thinking about moving towards these transitional approaches I think are really great.
Say you have a react app or any framework anywhere it emits HTML It could just as easily emit a custom element and that custom element could carry its own behavior and just business concerns on its own and then maybe one day when that framework is replaced by another, you've still got code that's standard and doesn't need to change, right?
Or it could work in this other page that doesn't use a framework at all.
When you do start a new project, that needs some high level orchestration around all your web components, there are some pretty good options out there right now.
Enhance.
Dev, webc and lit. I recommend looking up, all three of those.
They have very different and interesting approaches, to building with custom elements and, composing them, often on the server side, especially with enhance, which is really nice.
A couple things, upcoming that we should keep our eye out for with Web Components.
Declarative custom elements, this is gonna be pretty exciting.
Again, this is all, coming out of the community group right now.
People are talking about ideas, to make working with Web Components even better and more robust, especially for, people trying to replace their framework and finding, this isn't quite what I need yet, right?
This feature will allow us to declare, custom element behaviors without writing JavaScript.
And that's nice cause we could do it on the server side.
This is not real markup.
It's like aspirational, but you can see how it's like a template element that's defining my counter, and then I reuse my counter over and over.
So that could be potentially instead of saying custom elements define and write the whole script out, right?
This could apply a lot sooner than the JavaScript that has to run a little later.
DOM parts are another one that's upcoming that I'm pretty excited about.
Everywhere that the template element falls short with, not being real templating like you're used to in a, framework, this could potentially solve that, problem.
It gives us variables in HTML, that we can work with.
And this is, this is potentially coming soon, right?
So it's like maybe a year from now, we could be, using things like this in the browser without a framework.
And then there's signals.
Lex gave a talk about that yesterday.
Signals, give us a way to get reactive state in the browser without a framework.
So like the three of those features together are really going to bring a powerful set of features to, Web Components pretty soon.
To wrap up, Web performance varies a lot, today for people depending on their circumstances, right?
Devices and network speeds, vary widely, and that contributes to that.
Our, practices, our JavaScript over defendant practices have really exacerbated that problem.
We're just relying on JavaScript too much, and we're shipping too much of it.
Web Components?
Are not going to save us from this situation on their own.
They can't do it automatically.
But what they can do, I think, is give us an opportunity to rethink how we deliver our websites more resiliently and, more performantly.
And that's where you come in.
Thank you.
- JavaScript
- React
- HTML
- DOM
- server rendering
- critical optimizations
- INP (Interaction to Next Paint)
- Promises
- hydrating
- Web Components
- custom elements
- Shadow DOM
- UL
- LI
- CSS
- import/export modules
- script tag
- connectedCallback
- event listeners
- attributes
- template elements
- render function
- CSS custom properties
- declarative Shadow DOM
- attachShadow
- querySelectorAll
- slots
- standards path
- images
- JavaScript disabled
- CSS anchors
- stylable select elements
- web standards
- view transitions
- responsive video
- signals