User Facing State

Let’s talk about state. Communicating state to the user that is, not application stores state in JavaScript objects, or localStorage. We’re going to be talking about how to let our users know about state (think: whether a button is disabled or not, or if a panel is active or not), and how we can use CSS for that. We’re not going to be using inline styles, or, as much as can be helped, class selectors, for reasons that will become clear as we go.

Still here? Cool. Let’s do this.

All dynamic components of an application have a default user-facing state, and that state needs to be stored and updated as users interact with these components.

For example, when a button is pressed, things happen (that’s what buttons are for). When these things happen, they are typically represented in a visual manner in the interface. The button’s background may change to indicate it was pressed. If the button controls other components in the interface, those components likely visually change in style, or in some cases their visibility is toggled. An item gets deleted, a notification pops up, an error style is applied, etc.

You may have noticed that we’ve been mentioning the “visual” state of components quite a bit. That’s exactly the kind of problem I’ve been finding with a lot of tutorials, articles and general talking about state.

More often than not, developers are using “stateful” classes to manage a component’s state. But this is sorely inadequate, as a component is composed of more than just how it looks. There are underlying semantics that need to be managed along with the component’s visual representation. The failure to manage those underlying semantics becomes apparent as soon as you interact with it via keyboard and/or screen reader.

This is an article about appropriately conveying state so that users, beyond sighted, mouse-using users, can interact with our interfaces.

State is more than just how it looks

Outside of using CSS to appropriately hide content from sighted users and assistive technologies, CSS doesn’t have many intentional effects on an element’s semantics or accessible state. What I mean by that is outside of properties like the unsupported ‘speak’ , before/after pseudo content, and media queries to specifically restyle components based on user preferences, like the Reduced Motion Media Query and other proposed User Queries , CSS alone is not meant to change an element’s semantics, content or appropriately convey the state of an element in a meaningful way.

Why do I bring all this up? Because managing state with CSS classes alone is, mostly, inadequate for conveying state to all users. Being a language for presentational purposes, giving an input a class of .has-error to change the border color to a shade of red, has no semantic value to it. For all CSS cares, “That’s how you wanted to style that input. Cool. I got your back! Just don’t ask me to style upwards in the DOM. I draw the line there, buddy…”

Instead, to manage and convey state, we should be updating attributes on the appropriate elements. And no, I don’t mean data-attributes. Those don’t mean anything either. If we take this approach, in many cases we won’t even need stateful classes, outside of classes that toggle an element’s display.

Did we forget we can style with attribute selectors?

HTML and ARIA have a whole bunch of attributes that should be used to appropriately convey the current state of a component.

Thinking about using an .is-disabled class on your

I'm sure you have your own opinion...