Web components are an exciting technology that allows developers to create self-contained, reusable code patterns that are easy to control and update.
The idea of web components is not new, nor is it unique to JavaScript frameworks. Web components are incorporated into the official W3C specification and with some of the trickier particulars around implementation smoothed out, there’s been renewed interest in their use.
This forward progress means we’re pretty close to being able to use them without having to rely on libraries such as Polymer that add a lot of overhead to your project. That’s pretty exciting!
Note that for the purposes of this article, the term “web component” is shorthand for not only the W3C’s custom element, but also the variants implemented in libraries like, Angular, React, Vue, etc. I’m also not going to get into the deep details of how the Shadow DOM works, as that’s beyond the scope of this article.
Explanation
A good candidate for a web component could be a toggle. They’re a popular user interface design pattern that requires a specific markup implementation that needs to be copied from instance to instance, with little code changing save for the text label.
There’s a lot of different ways you can author this kind of pattern, some better than others:
<!-- Inacessible -->
<div class="button is-collapsed"></div>
<!-- Kind of okay, requires extra JavaScript -->
<div role="button" class="button">
Label text
</div>
<!-- Better! -->
<button aria-pressed="true" class="button">
Label text
</button>
Deciding on using only one bulletproof implementation means there’s less of a chance an inaccessible treatment and/or copy/paste bugs could sneak into the codebase. So how do we make this happen? First we create our HTML template, using semantic HTML and ARIA:
<button aria-pressed="true|false" class="toggle-button">
Label text
</button>
The button
element will announce its role to assistive technologies. aria-pressed
semantically describes the button’s state, and can be leveraged as a styling hook using CSS’s attribute selector. The label text provides the button with an accessible name.
Using JavaScript, we can then define this template as a custom element, with the pressed
and label
attributes corresponding to the aria-pressed
and button label text. Another neat thing we can do is ensure our toggle buttons always have an accessible name by writing our JavaScript logic in such a way that it will report an error if a value for the label
attribute isn’t provided.
All custom elements need to have a dash character (-
) in their name, otherwise they’ll be flagged as invalid HTML. Because of this, we’ll call the custom element toggle-button
:
<toggle-button pressed="true|false" label="Label text">
toggle-button
will then serve as a hook for additional JavaScript that will swap it out with our predefined chunk of code. Other JavaScript can hook into toggle-button
‘s pressed
attribute and toggle it when the user activates the button.
The toggle-button
component can then be declared in different template files. Updates to the source toggle-button
code—say adding logic for including an icon—will then be consistently updated everywhere the component is used. Always using this canonical toggle button implementation keeps things consistent, helping to prevent liability, tech debt, and payload bloat from entering into a project’s codebase. This is the power of web components.
This a somewhat simple example, but it demonstrates how you can define a single source of truth and then propagate it through a website or web app.
Concerns
Putting aside worries about the fragility of and over-reliance on JavaScript for a moment, there is one vital thing I want to stress:
The code you place inside your web component needs to be accessible.
There seems to be a prevailing notion that using fancy modern development techniques somehow absolves you of the need to build with a robust, accessible mindset. It is incredibly troubling.
Developer convenience shouldn’t take priority over user experience. While setting up web components will allow you to create pages and views quickly and efficiently, all of this fancy pre-configuration is lost on the end user. Web components ultimately render as HTML, and either that HTML works or it doesn’t.
When I say works, I mean that it works for everyone, regardless of their device or ability. Start with a progressively enhanced core, using the semantic HTML markup that best exposes native semantics to assistive technology (AT). It is also equally important to test what you write with actual assistive tech to verify what you wrote works as expected—like any other software, there are bugs and gotchas to look out for.
You can have your cake and eat it too! Let HTML do what it does best: creating interoperable, fault-tolerant, and future-friendly experiences. Let web components do what they’re good at: making consistent, easily modifiable, developer-friendly components.
Authoring
Most of the things you’d want to do on the web—go places, push buttons, check off items, type words, make selections, etc.—already have a representative native element, ready and waiting to be used.
While it may seem tempting to use easy-to-style div
s and span
s to create the components required to perform these actions, it will take far more JavaScript to recreate what the browser gives you for free for just using the relevant native HTML element. And even then, you may not be able to successfully recreate all expected behavior, say how select
elements behave on mobile.
Don’t needlessly reinvent the wheel. These native elements are far more fault tolerant than any custom solution, accommodating the years of corner cases you’ll fail to think of in a single product sprint. More fault tolerance means less work and less risk down the road, both things I find highly appealing.
When authoring your next (or first!) web component, take a moment to review the following:
- The HTML elements, their intended uses, and their attributes (especially for input).
- Speaking of input, start with elements that can natively receive keyboard focus for anything a user can interact with:
a
,button
,details
,summary
, andlabel
with aninput
,select
ortextarea
. - Check to see if there are any tried-and-true, accessible implementations of the kind of component you want to create.
- Test with actual assistive technology to make sure your web component functions the way you intended it to.
Why should I care?
Single Page Applications (SPAs) are now the go-to model for building experiences on the web. Things like web components and template views feature heavily in most of the popular SPA frameworks.
And that’s fine! If your use case matches the need for an app-like experience, it’s totally possible to use a SPA framework and make the experience friendly for people who use AT. Again, all of this ultimately renders as HTML, and when it comes to AT-friendly markup some HTML declarations are better than others.
Accessibility is a core principle of the web. Just because the way we’re building websites and web apps is changing doesn’t mean it’s acceptable to lock some people out. Semantic, accessible HTML is the quiet, reliable foundation that enables you to build anything you want with confidence.
There isn’t any real industry-shattering revelation or mind-blowing coding trick in this article. To be honest, I’m hoping that it’s one of those things you, a person who understands the importance of accessibility, can show someone else to help reinforce your argument.