CSS selectors are awesome.

If you already use newish selectors on a daily basis, then what follows will probably seem very mundane by now (5 years after the release of Selectors Level 3). I don't use complex selectors much1, so I'm still occasionally blown away by how incredible they've become. Today was such an occasion.

So I have this grid of films I'm watching:2

A grid of posters of films I've watched recently

Film names aren't displayed as plain text on the page, to avoid breaking the grid's alignment). But when a film has a crypic poster, or for searching through the list using CMD + F, a toggle to show/hide film names would be helpful.

Using something like React, this would be as simple as saving the toggle's value in state and conditionally rendering film names:

function FilmsGrid(films) {
  const [showNames, setShowNames] = useState(false);
  return (
    <>
      <label htmlFor="toggle">Show film names</label>
      <input
        id="toggle"
        type="checkbox"
        checked={showNames}
        onChange={() => setShowNames(!showNames)}
      />
      <ul>
        {films.map((film) => (
          <li key={film.name}>
            <img src={film.posterUrl} alt={film.name} />
            {showNames && film.name}
          </li>
        ))}
      </ul>
    </>
  );
}

Done.

But you might know that this website doesn't use any kind of JavaScript framework. The few lines of JS on here are painstakingly written in old-fashioned <script> tags, mutating the DOM directly with things like document.getElementById("thing-to-update").innerText = "New content!". Turns out that this is a good incentive to reach for web technologies in the intended order: HTML first, CSS next, and JS last.3

And for this toggle, only HTML and CSS are really necessary. I ended up building it with a handful of semantic HTML elements...

<input id="toggle" type="checkbox" />
<label htmlFor="toggle">Show film names</label>
<ul>
  <!-- the data is populated at build time -->
  <li>
    <img src="poster.jpg" alt="Film name" />
    <span class="film-name">Film name</span>
  </li>
</ul>

...and the CSS selector magic that I was mentioning at the top of this note:

/* if the checkbox is not checked, we hide film names */
#toggle:not(:checked) ~ ul li .film-name {
  display: none;
}

Here it is! A simple, React-less, JS-less visibility toggle.

CSS selectors are awesome!

Footnotes

  1. We mostly use CSS-in-JS in my org, and CSS-in-JS isn't exactly known to embrace the cascade.

  2. Screenshot from a previous post about building the grid.

  3. Needless to say that using [insert JS framework] should not be a default for small, largely static websites like this one.