One of the reasons I can’t stop thinking about native Web Components is how you can use them anywhere. “Incremental adoption” is the fancy phrase, I suppose.
We’ve even started using them on the new editor for CodePen we’re still hard at work on to solve some interesting issues I’m sure we’ll talk about someday. We’re using React/Next there, which isn’t famous for it’s support of Web Components, but it’s mostly been fine. Other JavaScript frameworks are much more friendly, and of course if you aren’t using a JavaScript framework you haven’t a care in the world; Web Components can be part of your world.
Because they are pretty easy to slip in anywhere, they work pretty well on CodePen. I mentioned a list of “stand alone” Web Components the other week here at the ol’ Corner, then I converted them into Pens just to prove that. A lot of web components are published to npm to using a site like esm.sh makes linking up the resources pretty easy.
What’s cool about using web components like I have above is that they just might last forever. I ranted a little about this on Mastodon the other day. The fewer dependencies a web component has, the longer it will last. It will certainly outlive your JavaScript framework, as Jake Lazaroff put it:
If we want our work to be accessible in five or ten or even 20 years, we need to use the web with no layers in between. For all its warts, the web has become the most resilient, portable, future-proof computing platform we’ve ever created — at least, if we build with that in mind.
I think that’s cool.
I makes me think what will break about those demos I posted. Like, what is going to make this Pen stop working someday? If CodePen goes offline, it will. But we’ve just had our 12th birthday are are going strong. You’d have to fight me to the death for that to happen. The web component is linked up from esm.sh
so if that went down it would stop working. That’s definitely possible, we’ve seen free CDN-like websites like this come and go. But you could just change to a different one. The code is on npm, so that could die or the author could pull it down. But there doesn’t seem to be a lot of risk of that, and it’s open source so mirrors will exist. Pretty resilient, I’d say! Although different projects have different needs there and you could always get stronger by reducing even those dependencies.
Oh hey speaking of web components and things that are super cool… check out David Darnes new one just for us: <code-pen>
.
The idea is that it’s a convienient way to use our Post to Prefill API. So you’d author code like this:
<script type="module" src="code-pen.js"></script>
<code-pen>
<pre>
<code><p>Hello world</p></code>
</pre>
<pre>
<code>:root { color: hotpink; }</code>
</pre>
<pre>
<code>document.querySelector("p").style.backgroundColor = "orange";</code>
</pre>
</code-pen>
(Or you could use Markdown triple backticks and avoid the code escaping, among other options)
Then it builds an “Open in CodePen” button that users can click to open that code in a real Pen. The point is usually stuff like documentation and blog posts where you want to manage all the code yourself, not maintain both the text and the Pens separately. Thanks David, this is super cool.
David also recently published a free eBook called The Case for Web Components you might want to check out if you’re looking to be further convinced or need more learnings on the basic to decide. In it, he mentioned the use case of “design systems”, which seems like an awful big one to me. These days, if you’re creating a design system, doing it in anything other than web components seems weird. Web components will last and be movable between frameworks as your project evolves, with little if any downside.
While we’re on the subject let’s just get a little more into the weeds.
Ultimately a Web Component is a class
in JavaScript. It has standard methods, like a constructor
that is called when the class is instantiated. It also has a method connectedCallback
that runs when on each instance of a web component when it shows up in the DOM. This is a bit of a subtle difference and can be quite a gotcha, as Nolan Lawson says. If your component needs to do stuff that might be unique to each instance, that belongs in connectedCallback
. I think it’s a real superpower of web components! For example, it’s kinda like getting event delegation for free.
There is an approach to web components called HTML web components which is essentially:
- Take some perfectly acceptable HTML
- Wrap it in a
<web-component>
to extend the functionality
That’s fun and obviously useful (e.g. a blog post with a web component would render fine over RSS). It’s related but not quite the same declarative shadow DOM. Raymond Camden explores something interesting here… how does a web component know if the HTML inside it changes? Unfortunately there is no obvious solution or helper API for this… other than the platform itself. The trick is that you use a MutationObserver
on itself internally to watch for changes and then do whatever you gotta do. Interesting stuff. I’d be tempted to rip the whole thing out of the DOM and replace it just so connectedCallback
does it’s thing, rather than craft every web component such that it’s watching for it’s own changes.
I hadn’t really thought that much about watching for changes like that before, as it just hasn’t come up for me. Similarly, Ben Nadel points out that the contents of a <template>
can be mutated at any time, and new components instantiated off it will use that new content. That makes sense to me, it’s just a twist of how I normally think of components. I think of the template as this static thing which takes data and does what it needs to do. Less so do I think of a template itself that is dynamic based on data.