HTML Data Attributes for Designer State Management
State Management in Web Design
What is State?
Think about a simple light switch. It has two conditions: on or off. The current condition of that switch, whether it's on or off, is its 'state.'
In web design, components on a page also have states. A drop-down menu can be open or closed. A button can be in its normal state, a 'hovered over' state, or a 'clicked' state. A form field might be empty, filled out, or showing an error. State is simply the current condition of any piece of your user interface.
State is what makes a static webpage feel alive and interactive. It keeps track of all the little changes that happen as a user clicks, types, and moves around the screen.
Without a way to manage these changes, every webpage would be a fixed document, like a page in a book. To create the dynamic experiences we expect from modern websites, we need a way to track and update state. This is where JavaScript comes in. It acts as the brain, listening for user actions and changing the state of elements accordingly.
Managing State with Classes
A common, long-standing method for managing state is to use HTML classes. The idea is simple: a class is added to an element to represent a certain state, and removed when that state is no longer active. For example, a pop-up modal might have a class of .is-hidden by default. When a user clicks a button to open it, JavaScript removes that class, and the modal appears.
This approach works well because it separates responsibilities. HTML provides the structure, CSS handles the appearance based on which classes are present, and JavaScript is only responsible for toggling those classes. It doesn't need to know anything about colors, fonts, or positioning.
We delegated all styling and display tasks to the CSS alone, using JavaScript to simply alter the “status” of elements by adding and removing CSS classes, as opposed to hiding and showing the elements with JavaScript directly.
Let's see this in action. Here we have a button that reveals a hidden message.
<!-- HTML: The Structure -->
<button id="toggleButton">Show Message</button>
<div id="message" class="hidden">
<p>Surprise! Here is the secret message.</p>
</div>
/* CSS: The Style */
.hidden {
display: none;
}
// JavaScript: The Brains
const button = document.getElementById('toggleButton');
const message = document.getElementById('message');
button.addEventListener('click', () => {
message.classList.toggle('hidden');
});
In the code above, the div starts with the hidden class, and our CSS rule makes any element with that class invisible. When the button is clicked, our JavaScript code simply toggles the hidden class on the div. If the class is there, it's removed. If it's not, it's added. Simple and effective.
When Classes Get Complicated
This class-based method works beautifully for simple on/off states. But what happens when an element has multiple, independent states at the same time? Imagine a 'Submit' button on a form. It could be in a loading state after you click it. It could also be in a disabled state if some form fields are invalid. And it might have an error state if the submission fails.
Now, our JavaScript has to juggle multiple classes: .is-loading, .is-disabled, .has-error. Which classes can exist at the same time? Does adding .is-loading mean we should remove .has-error? The logic starts to get messy.
Using classes alone can lead to confusing code when you need to manage several states that don't depend on each other. Your JavaScript can become a complex web of
ifstatements just to figure out which classes to add or remove.
This complexity is a sign that we're pushing the limits of what class-based state management is good for. While it's a fundamental technique every web developer should know, it's also the stepping stone to more powerful and organized ways of handling state in complex applications.
