An Innovative Idea for Holding State in CSS
Tags: css, statemachines, tutorial, programming
Published: 2022-01-15 21:16:03

When it comes to CSS and HTML, application state falls into these categories:
**cascade state**: classes/checkbox state/other dom
![screenshot of html and css producing a static state](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggpsz9m92dc5p3gk43az.png)
**pseudo state**: based on current user interaction
![gif showing HTML and CSS with a user interacting to trigger a temporary hover state](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qh0ighr17we4ykcgrc19.gif)
**animation state**: pre-determined series, triggered by cascade and/or pseudo state
![gif showing a CSS animation triggered by clicking a checkbox](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9hf7ek1sq3prnn86ltgs.gif)
**transition state**: easing between the cascade and/or pseudo states when they change
![gif showing CSS transition triggered by hover](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64f3a40mgxrbrt3wnnzl.gif)

These are the building blocks for all UX that can be combined in an infinite number of ways<sup>[1]</sup>. These are all intertwined of course, and we can split hairs on how I've referred to them, but ultimately though; Either our state is _static_ - derived from the current DOM, or it's _temporary_ - derived from the user's current interaction.

<sub>[1] except that animation state cannot be combined with animation state due to [animation-tainting](https://www.w3.org/TR/css-variables-1/#animation-tainted)</sub>

> "But wait, there's more!"

\- @rockstarwind, probably


## The new static state, stored in CSS (not DOM!)


Earlier this week, @rockstarwind posted an idea on their twitter that [demonstrates a new technique for remembering temporary interactions](https://twitter.com/RockStarwind/status/1481565710350524416) without DOM needing to be the source of that memory (like it is with the :checked state of a checkbox).
They go on to show a reduced example in a codepen with excellent comments to learn from:
{% codepen https://codepen.io/RockStarwind/pen/YzrROPP default-tab=css,result %}

Neat!

Let's break down the idea and play with it a bit.

### Register the one-bit memory cell

Following their work, this is what we have to do first:
```css
@keyframes memory {
  0% { --cell: initial }
  1%, 100% { --cell: ; }
}
```

Using this `memory` animation sets the custom property `--cell` as a [Space Toggle](https://github.com/propjockey/css-sweeper#css-is-a-programming-language-thanks-to-the-space-toggle-trick) which has two states, off 'initial' and on ' '.

---

{% details The TL;DR of Space Toggles %}

You can concatenate CSS custom properties like so:
```css
.demo {
--val1: 2px solid;
--val2: red;
--result: var(--val1) var(--val2);
}
```
`--result` is effectively `2px solid red`

If you concatenate a space:
```css
.demo {
--toggle: ;
--value: green;
--result: var(--toggle) var(--value);
}
```
`--result` is effectively just `green`

If you concatenate initial:
```css
.demo {
--toggle: initial;
--value: green;
--result: var(--toggle) var(--value);
color: var(--result, cyan);
}
```
`--result` is invalidated and var(--result, fallback) will use the fallback instead. (color is set to cyan in this example)

So in effect, a space toggle is is a one bit variable we can use to derive two completely different states from reading it with `var()` wherever and as often as we want.

{% enddetails %}

---

Note: Animating custom properties is part of the Houdini spec, so this [may not work in firefox](https://ishoudinireadyyet.com/) for a while.

### Initialize the memory

All we have to do here is apply the keyframes to an element:
```css
.demo {
  animation-name: memory; /* keyframes reference */
  animation-duration: .1s;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
  animation-timing-function: linear;
  animation-play-state: paused; /* must be paused at first */
}
```

Using the shorthand animation property, that looks more like this:
```css
.demo {
  animation: memory 1ms linear 1 forwards paused;
}
```

Now `.demo` elements have a `--cell` property explicitly set to `initial`.

### Set up properties to use the space toggle

```css
.demo {
  --bg-if-cell-is-on: var(--cell) rebeccapurple;
  background: var(--bg-if-cell-is-on, hotpink);

  --color-on: var(--cell) white;
  color: var(--color-on, black);
}
```

In English, if the cell is off, the background is `hotpink` and color is `black`. If the cell is on, the background is `rebeccapurple` and color is `white`.

### Flipping the bit

Next, they use the `:active` pseudo state from a `button` to un-pause the animation. Theoretically we could use any pseudo state, like :hover.

Let's test

{% codepen https://codepen.io/propjockey/pen/b01b6646ba7d22e501fb3513f9a5cf1e default-tab=css,result theme-id=40148 %}

<sub>click 'rerun' in the bottom right corner if needed!</sub>

Great! If the user's pointer enters the document, CSS flips state and the background becomes rebeccapurple.

### Un-flipping the bit

To return to the initial state, the easiest way is what they've shown, set `animation: none;` on our element when a selector matches.
This changes `--cell` back to `initial` _implicitly_ because when a custom property is not set (nor [registered with a specific syntax](https://drafts.css-houdini.org/css-properties-values-api/#supported-names)), it is initial.

## The rest of the owl

We can use this technique to do something fun like 100% CSS etch-a-sketch:

{% codepen https://codepen.io/propjockey/pen/mdBvjgg default-tab=result theme-id=40148 %}

Delightful!

## "Remembering is so much more a psychotic activity than forgetting"

I've only been friends with RockStarwind for a couple years but they are continually sharing innovative ideas and awesome demos in the CSS space. Definitely give them a [follow on Twitter](https://twitter.com/RockStarwind) so you don't have to remember to check manually. ;)

If you enjoyed my first article, please consider following me here and [on twitter](https://twitter.com/Jane0ri) as well!

💜

## Prior art!
After tweeting, I learned about someone already using this idea in a really really interesting way! Check it out!
{% twitter 1482467007798951939 %}
and her demo:
{% codepen https://codepen.io/lillian-kodi/pen/NWgWQKR default-tab=result %}
HOW COOL IS THAT?!