Custom Element Naming | BitWorking
More thoughts on naming web components.
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.
I realized why I hadn’t yet added any rules to my
robots.txt
: I have zero faith in it.
I really like the idea of a shared convention for styling web components with custom properties—feels like BEM meets microformats.
Two-factor authentication is generally considered A Good Thing™️ when you’re logging in to some online service.
The word “factor” here basically means “kind” so you’re doing two kinds of authentication. Typical factors are:
Asking for a password and an email address isn’t two-factor authentication. They’re two pieces of identification, but they’re the same kind (something you know). Same goes for supplying your fingerprint and your face: two pieces of information, but of the same kind (something you are).
None of these kinds of authentication are foolproof. All of them can change. All of them can be spoofed. But when you combine factors, it gets a lot harder for an attacker to breach both kinds of authentication.
The most common kind of authentication on the web is password-based (something you know). When a second factor is added, it’s often connected to your phone (something you have).
Every security bod I’ve talked to recommends using an authenticator app for this if that option is available. Otherwise there’s SMS—short message service, or text message to most folks—but SMS has a weakness. Because it’s tied to a phone number, technically you’re only proving that you have access to a SIM (subscriber identity module), not a specific phone. In the US in particular, it’s all too easy for an attacker to use social engineering to get a number transferred to a different SIM card.
Still, authenticating with SMS is an option as a second factor of authentication. When you first sign up to a service, as well as providing the first-factor details (a password and a username or email address), you also verify your phone number. Then when you subsequently attempt to log in, you input your password and on the next screen you’re told to input a string that’s been sent by text message to your phone number (I say “string” but it’s usually a string of numbers).
There’s an inevitable friction for the user here. But then, there’s a fundamental tension between security and user experience.
In the world of security, vigilance is the watchword. Users need to be aware of their surroundings. Is this web page being served from the right domain? Is this email coming from the right address? Friction is an ally.
But in the world of user experience, the opposite is true. “Don’t make me think” is the rallying cry. Friction is an enemy.
With SMS authentication, the user has to manually copy the numbers from the text message (received in a messaging app) into a form on a website (in a different app—a web browser). But if the messaging app and the browser are on the same device, it’s possible to improve the user experience without sacrificing security.
If you’re building a form that accepts a passcode sent via SMS, you can use the autocomplete
attribute with a value of “one-time-code”. For a six-digit passcode, your input
element might look something like this:
<input type="text" maxlength="6" inputmode="numeric" autocomplete="one-time-code">
With one small addition to one HTML element, you’ve saved users some tedious drudgery.
There’s one more thing you can do to improve security, but it’s not something you add to the HTML. It’s something you add to the text message itself.
Let’s say your website is example.com and the text message you send reads:
Your one-time passcode is 123456.
Add this to the end of the text message:
@example.com #123456
So the full message reads:
Your one-time passcode is 123456.
@example.com #123456
The first line is for humans. The second line is for machines. Using the @ symbol, you’re telling the device to only pre-fill the passcode for URLs on the domain example.com. Using the # symbol, you’re telling the device the value of the passcode. Combine this with autocomplete="one-time-code"
in your form and the user shouldn’t have to lift a finger.
I’m fascinated by these kind of emergent conventions in text messages. Remember that the @ symbol and # symbol in Twitter messages weren’t ideas from Twitter—they were conventions that users started and the service then adopted.
It’s a bit different with the one-time code convention as there is a specification brewing from representatives of both Google and Apple.
Tess is leading from the Apple side and she’s got another iron in the fire to make security and user experience play nicely together using the convention of the /.well-known
directory on web servers.
You can add a URL for /.well-known/change-password
which redirects to the form a user would use to update their password. Browsers and password managers can then use this information if they need to prompt a user to update their password after a breach. I’ve added this to The Session.
Oh, and on that page where users can update their password, the autocomplete
attribute is your friend again:
<input type="password" autocomplete="new-password">
If you want them to enter their current password first, use this:
<input type="password" autocomplete="current-password">
All of the things I’ve mentioned—the autocomplete
attribute, origin-bound one-time codes in text messages, and a well-known URL for changing passwords—have good browser support. But even if they were only supported in one browser, they’d still be worth adding. These additions do absolutely no harm to browsers that don’t yet support them. That’s progressive enhancement.
Claire L. Evans on computational slime molds and other forms of unconvential computing that look beyond silicon:
In moments of technological frustration, it helps to remember that a computer is basically a rock. That is its fundamental witchcraft, or ours: for all its processing power, the device that runs your life is just a complex arrangement of minerals animated by electricity and language. Smart rocks.
The evolution of affordances on the web:
The URL for a page goes at the top. Text appears in a vertically scrolling column. A dropdown menu has a downward-pointing triangle next to it. Your mouse cursor is a slanted triangle with a tail, and when you hover over a link it looks like Mickey Mouse’s glove.
Most of these affordances don’t have any relationship to the physical characteristics of the interaction they mediate. But remove them from a website, application, or interface, and users get disoriented, frustrated, and unproductive.
Mike sees the church of JS-first ignoring the lessons to be learned from the years of experience accumulated by CSS practitioners.
As the responsibilities of front-end developers have become more broad, some might consider the conventions outlined here to be not worth following. I’ve seen teams spend weeks planning the right combination of framework, build tools, workflows and patterns only to give zero consideration to the way they architect UI components. It’s often considered the last step in the process and not worthy of the same level of consideration.
It’s important! I’ve seen well-planned project fail or go well over budget because the UI architecture was poorly planned and became un-maintainable as the project grew.
We have to stop confusing the excesses of capitalism with the hallmarks of quality. Sometimes Google aren’t better, they’re just more pervasive.
cough AMP cough
Don’t write
fopen
when you can writeopenFile
. WritethrowValidationError
and notthrowVE
. Call that namefunction
and notfct
. That’s German naming convention. Do this and your readers will appreciate it.
A few common gotchas when using BEM, and how to deal with them.
This is great advice from Lindsay Grizzard—getting agreement is so much more important than personal preference when it comes to collaborating on a design system.
When starting a project, get developers onboard with your CSS, JS and even HTML conventions from the start. Meet early and often to discuss every library, framework, mental model, and gem you are interested in using and take feedback seriously. Simply put, if they absolutely hate BEM and refuse to write it, don’t use BEM.
It’s all about the people, people!
Good advice on writing code that is understandable to your fellow humans (and your future self).
We tend to use a variant of BEM in our CSS at Clearleft. Glad to see that when we’ve hit these issues, we’ve taken the same approach.
A lovely little tour of eleven ubiquitous icons.
Josh takes an-depth look at the navigation design implications of touch/keyboard hybrid devices, coming to a similar conclusion as Luke and Jason:
Unfortunately, the top-of-screen navigation and menus of traditional desktop layouts are outright hostile to hybrid ergonomics. Tried-and-true desktop conventions have to change to make room for fingers and thumbs.
Want to test for a hybrid device? Tough luck. Instead, argues Josh, the best you can do is assume that any device visiting your site could be touch-enabled.