DEV Community

Cover image for State.js Tutorial: Creating Reusable UI Components with Pure CSS Reactivity
iDev-Games
iDev-Games

Posted on

State.js Tutorial: Creating Reusable UI Components with Pure CSS Reactivity

Modern frontend frameworks treat components as JavaScript objects, classes, or functions.

But what if you could build components using only HTML, CSS, and attributes — no JS logic, no virtual DOM, no build step?

That’s exactly what State.js enables.

State.js exposes HTML attributes as reactive CSS variables, letting you build fully reactive UI components using nothing but CSS.

In this article, you’ll learn how to build your first CSS‑reactive component using State.js.


What Is a “Component” in State.js?

In React, a component is a function.

In Vue, it’s an object.

In Svelte, it’s a compiled file.

In State.js, a component is simply:

An HTML element whose behavior is driven by CSS variables and State.js attributes.

No JavaScript logic.

No rendering engine.

No framework runtime.

Just HTML + CSS + State.js.


Example: A <ui-health-bar> Component

Let’s build a reusable health bar component.

HTML

<ui-health-bar 
  data-state 
  data-hp="75" 
  data-max="100">
</ui-health-bar>
Enter fullscreen mode Exit fullscreen mode

State.js automatically exposes:

  • --state-hp
  • --state-max
  • --state-hp-normalized
  • --state-hp-percent

These variables update reactively whenever the attributes change.


CSS

ui-health-bar {
  display: block;
  width: 200px;
  height: 20px;
  background: #333;
  border-radius: 4px;
  overflow: hidden;
  position: relative;
}

ui-health-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  width: var(--state-hp-percent);
  background: linear-gradient(to right, #4caf50, #8bc34a);
  transition: width 0.3s ease;
}
Enter fullscreen mode Exit fullscreen mode

This is the magic:

  • CSS reads the reactive variables
  • CSS handles the animation
  • CSS renders the component
  • State.js updates the variables

No JavaScript logic required.


Updating the Component

Add a button that reduces HP:

<button 
  data-state 
  data-state-bind="hp" 
  data-state-decrement="10">
  Take Damage
</button>
Enter fullscreen mode Exit fullscreen mode

When clicked:

  • data-hp decreases
  • State.js updates --state-hp
  • CSS recalculates --state-hp-percent
  • The bar animates automatically

This is reactivity without JavaScript logic.


Why This Works

State.js turns HTML attributes into live CSS variables.

CSS handles:

  • layout
  • animation
  • transitions
  • interpolation
  • gradients
  • transforms

State.js handles:

  • state changes
  • variable updates
  • triggers
  • binding
  • reactivity

Together, they form a CSS‑reactive component system.


Why This Is a Big Deal

This approach gives you:

✔ Zero JavaScript logic

Your component logic lives in CSS.

✔ Zero framework runtime

No virtual DOM.

No hydration.

No re-renders.

✔ Zero build step

Works in plain HTML files.

✔ Fully portable components

A <ui-health-bar> works anywhere HTML works.

✔ Native browser performance

CSS is GPU‑accelerated and instant.


Component API Design (Optional)

You can define your own component API:

<ui-health-bar 
  data-hp="50" 
  data-max="200">
</ui-health-bar>
Enter fullscreen mode Exit fullscreen mode

Or add more attributes:

<ui-health-bar 
  data-hp="50" 
  data-max="200"
  data-color="green"
  data-low="red">
</ui-health-bar>
Enter fullscreen mode Exit fullscreen mode

State.js exposes them all as CSS variables.


Conclusion

State.js lets you build components using:

  • HTML for structure
  • CSS for behavior
  • State.js for reactivity

This creates a new category of UI architecture:

CSS‑Reactive Components

Components powered by CSS variables instead of JavaScript logic.

If you want to build lightweight, portable, framework‑free UI — this pattern is a game changer.

Top comments (0)