Try text scaling support in Chrome Canary - Josh Tumath
There’s a new meta tag on the block. This time it’s for allowing system-level text sizing to apply to your website.
There’s a new meta tag on the block. This time it’s for allowing system-level text sizing to apply to your website.
An excellent example of an HTML web component from Eric:
Extend HTML to do things automatically!
He layers on the functionality and styling, considering potential gotchas at every stage. This is resilient web design in action.
Grrr… it turns out that browsers exhibit some very frustrating behaviour when it comes to the video element. Rob has the details…
If you’re a front-end developer and you don’t read Chris Ferdinandi’s blog, you should change that right now. Add that RSS feed to your feed reader of choice!
Lately he’s been posting about some of the thinking behind his Kelp UI library. That includes some great nuggets of wisdom around HTML web components.
First of all, he pointed out that web components don’t need a constructor(). This was news to me. I thought custom elements had to include this incantation at the start:
constructor () {
super();
}
But it turns that if all you’re doing is calling super(), you can omit the whole thing and it’ll be done for you.
I immediately refactored all the web components I’m using on The Session. While I was at it, I implemented Chris’s bulletproof web component loading.
Now technically, I don’t need to do this. I’m linking to my JavaScript at the bottom of every page so I know it’s going to load after the HTML. But I don’t like having that assumption baked into my code.
For any of my custom elements that reference other elements in the DOM—using, say, document.querySelector()—I updated the connectedCallback() method to use Chris’s technique.
It turned out that there weren’t that many of my custom elements that were doing that. Because HTML web components are wrapped around existing markup, the contents of the custom element are usually what matters (rather than other elements on the same page).
I guess that’s another unexpected benefit to HTML web components. Because they’ve already got their own bit of DOM inside them, you don’t need to worry about when you load your markup and when you load your JavaScript.
And no faffing about with the dark arts of the Shadow DOM either.
I’m obviously biased, but I like the sound of what Chris is doing to create a library of HTML web components.
This is clever: putting CSS inside a noscript element to hide anything that requires JavaScript.
dialog, details, datalist, progress, optgroup, and more:
If this article helps just a single developer avoid an unnecessary Javascript dependency, I’ll be happy. Native HTML can handle plenty of features that people typically jump straight to JS for (or otherwise over-complicate).
This is very nice HTML web component by Miriam, progressively enhancing an ordered list of audio elements.
It’s great to see the evolution of HTML happening in response to real use-cases—the turbo-charging of the select element just gets better and better!
So what are the advantages of the Custom Elements API if you’re not going to use the Shadow DOM alongside it?
- Obvious Markup
- Instantiation is More Consistent
- They’re Progressive Enhancement Friendly
React has become a bloated carcass of false promises, misleading claims, and unending layers of backwards compatibility – the wrong kind of backwards compatibility, as they still occasionally break your fucking code when updating.
Pretty much anything else is a better tool for pretty much any web development task.
This special in-depth edition of Quanta is fascinating and very nicely put together.
In an earlier era, startups could build on the web and, if one browser didn’t provide the features they needed, they could just recommend that their users try a better one. But that’s not possible on iOS.
I’m extremly concerned about the newest bug in iOS 18:
Whaa? That’s just shockingly dreadful!
This is an interesting thought from Scott: using Shadow DOM in HTML web components but only as a way of providing sort-of user-agent styles:
providing some default, low-specificity styles for our slotted light-dom HTML elements while allowing them to be easily overridden.
The mathematics behind the halting problem is interesting enough, but what’s really fascinating is the community that coalesced. A republic of numbers.
Generative AI is like the ultimate idea guy’s idea! Imagine… if all they needed to create a business, software or art was their great idea, and a computer. No need to engage (or pay) any of those annoying makers who keep talking about limitations, scope, standards, artistic integrity etc. etc.
So many of the problems and challenges of working with Web Components just fall away when you ditch the shadow DOM and use them as a light wrapper for progressive enhancement.
Some lovely HTML web components—perfect for progressive enhancement!
More thoughts on naming web components.
I’ve been deep-diving into HTML web components over the past few weeks. I decided to refactor the JavaScript on The Session to use custom elements wherever it made sense.
I really enjoyed doing this, even though the end result for users is exactly the same as before. This was one of those refactors that was for me, and also for future me. The front-end codebase looks a lot more understandable and therefore maintainable.
Most of the JavaScript on The Session is good ol’ DOM scripting. Listen for events; when an event happens, make some update to some element. It’s the kind of stuff we might have used jQuery for in the past.
Chris invoked Betteridge’s law of headlines recently by asking Will Web Components replace React and Vue? I agree with his assessment. The reactivity you get with full-on frameworks isn’t something that web components offer. But I do think web components can replace jQuery and other approaches to scripting the DOM.
I’ve written about my preferred way to do DOM scripting: element.target.closest. One of the advantages to that approach is that even if the DOM gets updated—perhaps via Ajax—the event listening will still work.
Well, this is exactly the kind of thing that custom elements take care of for you. The connectedCallback method gets fired whenever an instance of the custom element is added to the document, regardless of whether that’s in the initial page load or later in an Ajax update.
So my client-side scripting style has updated over time:
event.target.closest.None of these progressions were particularly ground-breaking or allowed me to do anything I couldn’t do previously. But each progression improved the resilience and maintainability of my code.
Like Chris, I’m using web components to progressively enhance what’s already in the markup. In fact, looking at the code that Chris is sharing, I think we may be writing some very similar web components!
A few patterns have emerged for me…
Naming things is famously hard. Every time you make a new custom element you have to give it a name that includes a hyphen. I settled on the convention of using the first part of the name to echo the element being enhanced.
If I’m adding an enhancement to a button element, I’ll wrap it in a custom element that starts with button-. I’ve now got custom elements like button-geolocate, button-confirm, button-clipboard and so on.
Likewise if the custom element is enhancing a link, it will begin with a-. If it’s enhancing a form, it will begin with form-.
The name of the custom element tells me how it’s expected to be used. If I find myself wrapping a div with button-geolocate I shouldn’t be surprised when it doesn’t work.
You can use any attributes you want on a web component. You made up the name of the custom element and you can make up the names of the attributes too.
I’m a little nervous about this. What if HTML ends up with a new global attribute in the future that clashes with something I’ve invented? It’s unlikely but it still makes me wary.
So I use data- attributes. I’ve already got a hyphen in the name of my custom element, so it makes sense to have hyphens in my attributes too. And by using data- attributes, the browser gives me automatic reflection of the value in the dataset property.
Instead of getting a value with this.getAttribute('maximum') I get to use this.dataset.maximum. Nice and neat.
My favourite web components aren’t all-singing, all-dancing powerhouses. Rather they do one thing, often a very simple thing.
Here are some examples:
aria-collapsable for toggling the display of one element when you click on another.play-button for adding a play button to an audio or video element.ajax-form for sending a form via Ajax instead of a full page refresh.user-avatar for adding a tooltip to an image.table-saw for making tables responsive.All of those are HTML web components in that they extend your existing markup rather than JavaScript web components that are used to replace HTML. All of those are also unambitious by design. They each do one thing and one thing only.
But what if my web component needs to do two things?
I make two web components.
The beauty of custom elements is that they can be used just like regular HTML elements. And the beauty of HTML is that it’s composable.
What if you’ve got some text that you want to be a level-three heading and also a link? You don’t bemoan the lack of an element that does both things. You wrap an a element in an h3 element.
The same goes for custom elements. If I find myself adding multiple behaviours to a single custom element, I stop and ask myself if this should be multiple custom elements instead.
Take some of those button- elements I mentioned earlier. One of them copies text to the clipboard, button-clipboard. Another throws up a confirmation dialog to complete an action, button-confirm. Suppose I want users to confirm when they’re copying something to their clipboard (not a realistic example, I admit). I don’t have to create a new hybrid web component. Instead I wrap the button in the two existing custom elements.
Rather than having a few powerful web components, I like having lots of simple web components. The power comes with how they’re combined. Like Unix pipes. And it has the added benefit of stopping my code getting too complex and hard to understand.
Okay, so I’ve broken all of my behavioural enhancements down into single-responsibility web components. But what if one web component needs to have awareness of something that happens in another web component?
Here’s an example from The Session: the results page when you search for sessions in London.
There’s a map. That’s one web component. There’s a list of locations. That’s another web component. There are links for traversing backwards and forwards through the locations via Ajax. Those links are in web components too.
I want the map to update when the list of locations changes. Where should that logic live? How do I get the list of locations to communicate with the map?
When a list of locations is added to the document, it emits a custom event that bubbles all the way up. In fact, that’s all this component does.
You can call the event anything you want. It could be a newLocations event. That event is dispatched in the connectedCallback of the component.
Meanwhile in the map component, an event listener listens for any newLocations events on the document. When that event handler is triggered, the map updates.
The web component that lists locations has no idea that there’s a map on the same page. It doesn’t need to. It just needs to dispatch its event, no questions asked.
There’s nothing specific to web components here. Event-driven programming is a tried and tested approach. It’s just a little easier to do thanks to the connectedCallback method.
I’m documenting all this here as a snapshot of my current thinking on HTML web components when it comes to:
I may well end up changing my approach again in the future. For now though, these ideas are serving me well.