Zach’s ugly mug (his face) Zach Leatherman

The Squirminal Web Component

October 28, 2023

A lightweight structural-only zero-dependency web component to progressively animate to reveal HTML content. I believe the name came from an awkward portmanteau of squirmy and terminal.

This one is a few years old (but I am currently cataloguing my web components) and was developed to fake an antique terminal for the web-based CLI used in the Your Year on Netlify project.

Screenshot image for


  • Works with prefers-reduced-motion
  • Works without JavaScript (fallback to full content)
  • Add a blinking cursor via <squirm-inal cursor>
  • Autoplay (only when visible) via <squirm-inal autoplay>
  • Works with text nodes inside any arbitrary HTML content.

Better than Before

When I worked on the slide deck for my Smashing Conference talk in 2021, I developed a similar mechanism to do this, but in a much less efficient way: each syntax highlighted character was wrapped in an additional wrapper element on the server!

I wrote about this in Queue Code—“Live” Code without Errors and you can play around with it on the demo below:

Screenshot image for

That approach leaned heavily into server rendering unnecessarily—the whole point of this effect required client interaction and the fallback experience was the original content in its entirety.

Lessons learned

Squirminal is a better approach that doesn’t require expensive DOM modification on the server and is much more powerful—it can work with any arbitrary HTML content (e.g. lists, images, tables, etc—it’s not limited to syntax highlighted text) and leaves the original content intact and unmodified before or without JavaScript.

There is an important lesson here—in this case the best progressive enhancement compromise involved less server rendering! Ultimately this use case and interaction required clientside interactivity, so it was okay to lean into that a bit more—while still building on a good progressive enhancement baseline.

This was an important reminder to me that progressive enhancement is a continuum of possible solutions—and it’s important to adjust where your solution lives on that continuum as needed and for your individual requirements (and hopefully your tools don’t force you into a corner before you can make those decisions).


class MyComponent extends HTMLElement {
	connectedCallback() {
		// web component stuff
		// web component stuff
		// web component stuff
		// web component stuff
		// web component stuff
		// web component stuff
		// web component stuff
		// web component stuff
if("customElements" in window) {
	customElements.define("my-component", MyComponent);

In the wild

Live Site Walkthrough

Here’s a demo screencast I recorded of my personal Your Year on Netlify flow.

Watch on YouTube: Walkthrough of the Your Year On Netlify Microsite

< Newer
A new Eleventy mascot from David Neal!
Older >
browser-window Web Component

Zach Leatherman IndieWeb Avatar for a builder for the web and the creator/maintainer of IndieWeb Avatar for https://www.11ty.devEleventy (11ty), an award-winning open source site generator. At one point he became entirely too fixated on web fonts. He has given 81 talks in nine different countries at events like Beyond Tellerrand, Smashing Conference, Jamstack Conf, CSSConf, and The White House. Formerly part of CloudCannon, Netlify, Filament Group, NEJS CONF, and NebraskaJS. Learn more about Zach »


IndieWeb Avatar for https://www.alvinashcraft.comMike-麥-Mai-v1.618 ???????? Rotten Apple Annie :prami:Baldur BjarnasonBruce B Anderson


DannyAndersShawn HolmesRustiet (Redrum) besedaWesley SoaresMike-麥-Mai-v1.618 ???????? Rotten Apple Annie :prami:EvanDave ???? :cursor_pointer:jake lazaroffBaldur BjarnasonMorbiCarlton Gibson ????????Ryuno-Ki
  1. Robb Knightmare

    Robb Knightmare

    @zachleat I’ve been using this for a while and it looks fantastic Echo: RSS Cross Poster

  2. Zach Leatherman

    Zach Leatherman

    @robb Awesome! I’ll link that from the blog post!

  3. Matheus Fantinel

    Matheus Fantinel

    @zachleat you mentioned it works with JavaScript, but not in web component form, right? With JS disabled it doesn't load anything, unfortunately. That's the main thing stopping me from going all-in on web components right now, and I'm not sure if it's “fixable”

  4. Zach Leatherman

    Zach Leatherman

    @fantinel a couple of muddled terms there, but this is what it looks like on the demo without JS (it just shows the content).

  5. Eric Portis

    Eric Portis

    @zachleat First I read this as "Squirm–I Am Not A Lawyer" but now I see my mistake, it's actually a portmanteau of "Squirm Criminal"

  6. Matheus Fantinel

    Matheus Fantinel

    @zachleat oh sweet! I think I had opened the "Queued Code" page instead ????‍♂️This is nice! Am I right in assuming that the web component isn't loading at all and is just behaving like a container div?

  7. Zach Leatherman

    Zach Leatherman

    @fantinel correct!

  8. Zach Leatherman

    Zach Leatherman

    @fantinel you’re right that the queuecode demo doesn’t work without JS ????—although I think that’s a bug and not a technical limitation

  9. Zach Leatherman

    Zach Leatherman

    @eeeps 1337 h4x0rs commit smooth criminal terminal crimes

  10. Eric Portis

    Eric Portis

    @zachleat You've been `banner`ed You've been `cowsay`ed By a squirmy terminal

Shamelessly plug your related post

These are webmentions via the IndieWeb and

Sharing on social media?

This is what will show up when you share this post on Social Media:

How did you do this? I automated my Open Graph images. (Peer behind the curtain at the test page)