Skip to main content

Journal

HTML with Superpowers (from Dave Rupert)

Here’s a great new presentation by Dave Rupert (of the Shop Talk show) in which he makes a compelling case for adopting Web Components. Not only do they provide the same benefits of encapsulation and reusability as components in proprietary JavaScript frameworks, but they also bring the reliability and portability of web standards, work without build tools, are suited to progressive enhancement, and may pave the way for a better web.

Dave begins by explaining that Web Components are based on not just a set of technologies but a set of standards, namely:

  • Custom Elements (for example <custom-alert>)
  • Shadow DOM
  • ES Modules
  • the HTML <template> element

Standards have the benefit that we can rely on them to endure and work into the future in comparison to proprietary technologies in JavaScript frameworks. That’s good news for people who like to avoid the burnout-inducing churn of learning and relearning abstractions. Of course the pace of technology change with web standards tends to be slower, however that’s arguably a price worth paying for cross-platform stability and accessibility.

Some of Web Components’ historical marketing problems are now behind them, since they are supported by all major browsers and reaching maturity. Furthermore, web components have two superpowers not found in other JavaScript component approaches:

Firstly, the Shadow DOM (which is both powerful and frustrating). The Shadow DOM provides encapsulation but furthermore in progressive enhancement terms it enables the final, enhanced component output which serves as an upgrade from the baseline Light DOM HTML we provided in our custom element instance. It can be a little tricky or confusing to style, however, although there are ways.

Secondly, you can use web components standalone, i.e. natively, without any frameworks, build tools, or package managers. All that’s required to use a “standalone” is to load the <script type=module …> element for it and then use the relevant custom element HTML on your page. This gets us closer to just writing HTML rather than wrestling with tools.

Dave highlights an education gap where developers focused on HTML, CSS, and Design Systems don’t tend to use Web Components. He suggests that this is likely as a result of most web component tutorials focusing on JavaScript APIs for JavaScript developers. However we can instead frame Web Component authoring as involving a layered approach that starts with HTML, adds some CSS, then ends by applying JavaScript.

Web Components are perfectly suited to progressive enhancement. And that progressive enhancement might for example apply lots of complicated ARIA-related accessibility considerations. I really like the Tabs example where one would create a <generic-tabs> instance which starts off with simple, semantic, resilient HTML that renders headings and paragraphs…

<generic-tabs>
  <h2>About</h2>
  <div>
    <p>About content goes here. Lorem ipsum dolor sit amet…</p>
  </div>

  <h2>Contact</h2>
  <div>
    <p>Contact content goes here. Lorem ipsum dolor sit amet…</p>
  </div> 
</generic-tabs>

…but the Web Component’s JavaScript would include a template and use this to upgrade the Light DOM markup into the final interactive tab markup…

<generic-tabs>
  <h2 slot="tab" aria-selected="true" tabindex="0" role="tab" id="generic-tab-3-0" aria-controls="generic-tab-3-0" selected="">About</h2>
  <div role="tabpanel" aria-labelledby="generic-tab-3-0" slot="panel">
    <p>About content goes here. Lorem ipsum dolor sit amet…</p>
  </div>
  <h2 slot="tab" aria-selected="false" tabindex="-1" role="tab" id="generic-tab-3-1" aria-controls="generic-tab-3-1">Contact</h2>
  <div role="tabpanel" aria-labelledby="generic-tab-3-1" slot="panel" hidden>
    <p>Contact content goes here. Lorem ipsum dolor sit amet…</p>
  </div>
</generic-tabs>

The idea is that the component’s JS would handle all the complex interactivity and accessibility requirements of Tabs under the hood. I think if I were implementing something like Inclusive Components’ Tabs component these days I’d seriously consider doing this as a Web Component.

Later, Dave discusses the JavaScript required to author a Custom Element. He advises that in order to avoid repeatedly writing the same lengthy, boilerplate code on each component we might use a lightweight library such as his favourite, LitElement.

Lastly, Dave argues that by creating and using web components we are working with web standards rather than building for a proprietary library. We are creating compatible components which pave the cowpaths for these becoming future HTML standards (e.g. a <tabs> element!) And why is advancing the web important? Because an easier web lowers barriers: less complexity, less tooling and setup, less gatekeeping—a web for everyone.

How to debug event listeners with your browser’s developer tools (on Go Make Things)

On the page, right-click the element you want to debug event listeners for, then click Inspect Element. In chromium-based browsers like MS Edge and Google Chrome, click the Event Listeners tab in Developer Tools. There, you’ll see a list of all of the events being listened to on that element. If you expand the event, you can see what element they’re attached to and click a link to open up the actual event listener itself in the JavaScript.


Conditional border-radius in CSS (by Ahmad Shadeed via CSS-Tricks)

Here’s a “media query free” CSS one-liner which lets you set an element to have no border-radius when it is the full width of the viewport, but otherwise to have a border-radius.

It uses the same 9999 multiplication technique as Every Layout do to create a toggle.

Great for Card components which need to be full-width and non-rounded only on narrow viewports.

Design Engineering, on the Clearleft Podcast

Loved this short listen from Clearleft, on a subject close to my heart! New job titles can feel a bit “emperor’s new clothes” but with Design Engineering I think Clearleft, GitHub et al. might be onto something. It was fascinating hearing people from both design and engineering backgrounds give their perspectives, and how ultimately they’re addressing the same thing—the need to “finesse the overlaps/gaps” between design and the realisation of that design in engineering, especially in light of the complexities of the modern front-end.

(via @Stugoo)

Broken Copy, on a11y-101.com

Here’s an accessibility tip that’s new to me. When the content of a heading, anchor, or other semantic HTML element contains smaller “chunks” of span and em (etc), the VoiceOver screen reader on Mac and iOS annoyingly fails to announce the content as a single phrase and instead repeats the parent element’s role for each inner element. We can fix that by adding an inner “wrapper” element inside our parent and giving it role=text.

Make sure not to add this role directly to your parent element since it will override its original role causing it to lose its intended semantics.

The text role is not yet in the official ARIA spec but is supported by Safari.

(via @Seraphae and friends on Twitter)

Motion One: The Web Animations API for everyone

A new animation library, built on the Web Animations API for the smallest filesize and the fastest performance.

This JavaScript-based animation library—which can be installed via npm—leans on an existing web API to keep its file size low and uses hardware accelerated animations where possible to achieve impressively smooth results.

For fairly basic animations, this might provide an attractive alternative to the heavier Greensock. The Motion docs do however flag the limitation that it can only animate “CSS styles”. They also say “SVG styles work fine”. I hope by this they mean SVG presentation attributes rather than inline CSS on an SVG, although it’s hard to tell. However their examples look promising.

The docs website also contains some really great background information regarding animation performance.

Testing ES modules with Jest

Here are a few troubleshooting tips to enable Jest, the JavaScript testing framework, to be able to work with ES modules without needing Babel in the mix for transpilation. Let’s get going with a basic set-up.

package.json

…,
"scripts": {
  "test": "NODE_ENV=test NODE_OPTIONS=--experimental-vm-modules jest"
},
"type": "module",
"devDependencies": {
  "jest": "^27.2.2"
}

Note: take note of the crucial "type": "module" part as it’s the least-documented bit and your most likely omission!

After that set-up, you’re free to import and export to your heart’s content.

javascript/sum.js

export const sum = (a, b) => {
  return a + b;
}

spec/sum.test.js

import { sum } from "../javascript/sum.js";
    
test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

Hopefully that’ll save you (and future me) some head-scratching.

(Reference: Jest’s EcmaScript Modules docs page)

Harry Roberts says “Get Your Head Straight”

Harry Roberts (who created ITCSS for organising CSS at scale but these days focuses on performance) has just given a presentation about the importance of getting the content, order and optimisation of the <head> element right, including lots of measurement data to back up his claims. Check out the slides: Get your Head Straight

While some of the information about asset loading best practices is not new, the stuff about ordering of head elements is pretty interesting. I’ll be keeping my eyes out for a video recording of the presentation though, as it’s tricky to piece together his line of argument from the slides alone.

However one really cool thing he’s made available is a bookmarklet for evaluating any website’s <head>:
— ct.css

The accessibility of conditionally revealed questions (on GOV.UK)

Here’s something to keep in mind when designing and developing forms. GOV.UK’s accessibility team found last year that there are some accessibility issues with the “conditional reveal” pattern, i.e. when selecting a particular radio button causes more inputs to be revealed.

The full background story is really interesting but the main headline seems to be: Keep it simple.

  1. Don’t reveal any more than a single input, otherwise the revealed section should not be in a show-and-hide but rather in its own form in the next step of the process.
  2. Conditionally show questions only (i.e. another form input such as Email address)—do not show or hide anything that’s not a question.

Doing otherwise causes some users confusion making it difficult for them to complete the form.

See also the Conditionally revealing a related question section on the Radios component on the GDS Design System