State.js introduces a new way to build reactive UI:
HTML holds the data.
CSS reacts to the data.
Events change the data.
This tutorial explains how State.js listens to events, how you trigger state changes, and how to build interactive UI without writing JavaScript logic.
⭐ 1. What Is a State.js Event?
A State.js event is simply:
- a DOM event (click, input, mouseover, keydown, etc.)
- connected to a state mutation
- written declaratively in HTML
Example:
<div data-state
data-count="0"
data-state-on="click => count += 1"
data-state-text="Count: {count}">
</div>
When you click the element:
-
countincreases - State.js updates the attribute
- CSS variables update
- the text updates
All without JavaScript logic.
Learn more: State.js triggers
⭐ 2. The data-state-on Attribute
This is the core of the event system.
<div data-state
data-active="false"
data-state-on="click => active = !active">
</div>
This toggles the data-active attribute every time the element is clicked.
State.js then:
- updates CSS variables
- updates any bound text
- updates any reactive classes
⭐ 3. Listening to Any DOM Event
You can listen to any event the browser supports.
Click
data-state-on="click => count += 1"
Input
data-state-on="input => value = event.target.value"
Mouseover
data-state-on="mouseover => hovered = true"
Mouseout
data-state-on="mouseout => hovered = false"
Keydown
data-state-on="keydown => key = event.key"
State.js doesn’t invent new events — it uses the browser’s native ones.
Learn more: Event expressions
⭐ 4. Using Event Data (event)
State.js exposes the event object as event.
Example: capture the clicked element’s text.
<div data-state
data-last=""
data-state-on="click => last = event.target.textContent"
data-state-text="Last clicked: {last}">
</div>
Example: track mouse position.
<div data-state
data-x="0"
data-y="0"
data-state-on="mousemove => x = event.clientX; y = event.clientY"
data-state-text="X: {x}, Y: {y}">
</div>
⭐ 5. Updating Another Element’s State
Use data-state-target to update a different element.
<button
data-state-trigger
data-state-target="#box"
data-state-on="click => color = 'red'">
Make Red
</button>
<div id="box"
data-state
data-color="blue"
data-state-class="red: color == 'red'">
</div>
This is the State.js equivalent of:
- React props
- Vue emits
- Svelte dispatch
But simpler.
⭐ 6. Multiple Event Handlers
You can chain multiple events:
<div data-state
data-state-on="
click => count += 1;
mouseover => hovered = true;
mouseout => hovered = false
">
</div>
Each event runs its own expression.
⭐ 7. Using Events to Add/Remove Classes
<div data-state
data-active="false"
data-state-on="click => active = !active"
data-state-class="active: active">
</div>
This toggles a class with no JavaScript.
⭐ 8. Using Events to Drive CSS Animations
<div data-state
data-state-on="click => animate = true"
data-state-class="pop: animate">
</div>
CSS:
.pop {
animation: pop 0.3s ease;
}
This is how you build interactive UI without JS logic.
⭐ 9. Building a Mini App with Events
<div id="app"
data-state
data-count="0"
data-state-on="click => count += 1"
data-state-text="Clicked {count} times">
</div>
This is a complete app:
- reactive state
- reactive text
- event-driven logic
- no JavaScript
This is the State.js mental model.
⭐ 10. Why the Event System Matters
Because it replaces:
- React’s
onClick={() => setCount(count + 1)} - Vue’s
@click="count++" - Svelte’s
on:click={() => count++}
With:
data-state-on="click => count += 1"
No JS.
No framework.
No re-renders.
No hydration.
No build step.
This is the State.js philosophy.
Learn more: State.js architecture
Top comments (0)