Went down a rabbit hole today trying to share some CSS between a document (i.e. "light DOM") and the shadow DOMs of some #HTML custom elements (aka #WebComponents).
@cferdinandi I think #WebComponents are a great way to distribute parts of #DesignSystems, especially if you're dealing with varying frameworks and/or working with heavily polluted or legacy codebases.
However I do think that CSS is evolving at such a rate that Web Components will take more of a backseat when distributing design systems. They will still be present but mainly to provide JS behaviour (as they should) while more modern CSS will handle visual consistency
Inspired by the mention of Shiki by @chriscoyier in the Codepen Newsletter, I created a Web Component for quickly and easily using Shiki in any project, no tooling or complex builds required, works with all frameworks!
You will notice that the ArrayList class has an items property that is an array type. Lit won’t let you do something like <array-list items = ['Item 1', 'Item 2', 'Item 3']></array-list> but it is fine with you passing it in using javascript. That means that myList.items = ['Item 1', 'Item 2', 'Item 3']; does the job, fine.
@enhance_dev Backend agnostic server-side rendering (SSR) for Web Components
> https://enhance.dev is an HTML-first full-stack web framework that gives you everything you need to build standards-based multi-page web apps that perform and scale. #Enhance apps and their elements are server-side rendered for incredible performance and seamless progressive enhancement.
Using inline events handlers inside vanilla #WebComponents side project is kinda nice, what do you think? Love the freedom and joy of writing vanilla #JavaScript.
Earlier this week, when I wrote about how to build an autocomplete using Vue.js, it was less about exploring how to do it and more about documenting recent work that used Vuetify. I wanted to use today’s post to go in the other direction. Recently, I discovered the value of using Lit when writing Web Components. I wanted to see if we could go from the HTML / CSS example to a proper web component.
First crack at it
Lit is powerful. You can do a lot with it. Let’s start with a rewrite of Tuesday’s final example to one that uses just Lit.
The first thing that we do in this is to import LitElement, html, css from a CDN. Our CountySelector class extends LitElement and then customElements.define('county-selector', CountySelector) at the bottom of the page is what turns our class into a tag. The static styles definition is how you style the tag. You will notice that there aren’t any styles outside of that. The markup is all defined in render() near the bottom. The async fetchCounties() method gets the list of counties from the data.jws.app site that I created last week.
This works but web components are supposed to be reusable and this isn’t reusable enough, though.
You will notice that the big difference between this version and the first one is that we dropped the API call and replaced it with a countyList property that defines the options. We can do better, though.
In this next version, we eliminate all explicit references to counties since a person might presumably want to use the component for something other than counties. You might want to use it to prompt a user for ice cream flavors or pizza toppings.
How do you use Vue with a web component?
Unfortunately, you aren’t going to be able to use something like v-model with a web component. There are other ways to bind to form inputs, though. Let’s take a look.
In the above example, optionsList and selectedOption are defined as Refs. The ref object is mutable (you can assign new values to .value) and it is reactive (any read operations to .value are tracked, and write operations will trigger associated effects). The options list can be passed into the web component using the :optionsList property. You might notice, though that the example is using .join(', ') to convert the array to a comma-delimited list. That is because you can not pass an array directly into a web component. That is likely going to be the subject of a future article. You might also notice that it is triggering the when you click on a suggestion and onBlur. The dispatchEvent() method sends an event to the object, invoking the affected event listeners in the appropriate order. That should trigger updateSelectedOption when you select a county or finish typing one that isn’t in the list.
So, what do you think? Do you have any questions? Feel free to drop a comment, below.
This example defines <blog-feed></blog-feed> with a json parameter. Lit has a <a href="https://lit.dev/docs/components/lifecycle/#connectedcallback">connectedCallback()</a> lifecycle hook that is invoked when a component is added to the document’s DOM. Using that, we are running this.fetchBlogFeed() which in turn running await fetch(). It is then using https://lit.dev/docs/components/rendering/ to render the list items.