State.js gives you reactive state.
Keys.js gives you reactive keyboard input.
Together, they let you build interactive UI, controls, and even simple games using only HTML attributes, with no JavaScript logic.
This tutorial teaches:
- how Keys.js tracks keyboard state
- how State.js reacts to it
- how to bind keys to state
- how to build interactive UI
- how to animate with CSS
- how to build a small “move the box” demo
Let’s go.
⭐ 1. What Keys.js Actually Does
Keys.js listens to keyboard events and exposes them as:
- CSS variables
- HTML attributes
- classes
Example:
<div data-keys></div>
Keys.js automatically creates:
--keys-a: 1 or 0
--keys-space: 1 or 0
--keys-last: "a"
And adds classes like:
.keys-a
.keys-space
Learn more: Keys.js basics
⭐ 2. What State.js Does With That
State.js can react to:
- CSS variables
- attributes
- events
- conditions
So when Keys.js updates:
--keys-left: 1
State.js can use that to:
- update state
- change classes
- animate with CSS
- move elements
This is the reactive input pipeline:
Keyboard → Keys.js → CSS variables → State.js → UI
⭐ 3. Basic Setup
Include both libraries:
<script src="https://cdn.jsdelivr.net/npm/@idevgames/state-js/src/state.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@idevgames/keys-js/src/keys.min.js"></script>
Add the Keys.js root:
<div data-keys></div>
Now the entire page reacts to keyboard input.
⭐ 4. Detecting Key Presses with CSS
Let’s show when the user presses the spacebar.
<div class="indicator"
data-keys
data-state
data-state-class="active: keys.space">
Press SPACE
</div>
Explanation:
-
data-keys→ enable Keys.js -
keys.space→ true when space is pressed -
data-state-class="active: keys.space"→ add.activewhen pressed
CSS:
.indicator {
padding: 20px;
background: #444;
color: white;
transition: background 0.2s;
}
.indicator.active {
background: #4caf50;
}
This is a reactive UI element driven by keyboard input.
⭐ 5. Using Keys to Change State
Let’s increment a counter when the user presses ArrowUp.
<div id="counter"
data-state
data-count="0"
data-state-on="keys.arrowup => count += 1"
data-state-text="Count: {count}">
</div>
What happens:
- Keys.js fires a
keys.arrowupevent - State.js runs
count += 1 - UI updates automatically
This is the State.js event system in action.
Learn more: State.js event system
⭐ 6. Using Keys to Move an Element (No JS Logic)
Let’s build a simple “move the box” demo.
HTML
<div id="player"
data-state
data-x="100"
data-y="100"
data-state-on="
keys.arrowleft => x -= 5;
keys.arrowright => x += 5;
keys.arrowup => y -= 5;
keys.arrowdown => y += 5
">
</div>
CSS
#player {
width: 50px;
height: 50px;
background: dodgerblue;
position: fixed;
transform: translate(var(--state-x), var(--state-y));
}
What’s happening:
- Keys.js detects arrow keys
- State.js updates
data-xanddata-y - CSS moves the element using transforms
- No JavaScript logic
- No game loop
- No re-renders
This is DOM-native movement.
⭐ 7. Smooth Movement (Holding Keys)
Keys.js exposes “held down” state as CSS variables:
--keys-arrowleft: 1
We can use autofire to move continuously:
<div id="player"
data-state
data-x="100"
data-y="100"
data-state-autofire="
if keys.arrowleft then x -= 3 every 16ms;
if keys.arrowright then x += 3 every 16ms;
if keys.arrowup then y -= 3 every 16ms;
if keys.arrowdown then y += 3 every 16ms
">
</div>
This creates smooth WASD/arrow movement without JS.
Learn more: State.js intervals
⭐ 8. Using Keys to Trigger Animations
<div id="box"
data-state
data-state-class="jump: keys.space">
</div>
CSS:
#box.jump {
animation: jump 0.3s ease;
}
Pressing space triggers a CSS animation.
⭐ 9. Using Keys to Toggle UI
<div id="menu"
data-state
data-open="false"
data-state-on="keys.escape => open = !open"
data-state-class="visible: open">
Menu Content
</div>
Press ESC → open/close menu.
⭐ 10. Full Example — Move a Box + Change Color + Show Key
<div data-keys></div>
<div id="player"
data-state
data-x="100"
data-y="100"
data-color="blue"
data-state-on="
keys.arrowleft => x -= 5;
keys.arrowright => x += 5;
keys.arrowup => y -= 5;
keys.arrowdown => y += 5;
keys.space => color = 'red'
"
data-state-style="background: {color}">
</div>
<div id="info"
data-state
data-state-text="Last key: {keys.last}">
</div>
CSS:
#player {
width: 50px;
height: 50px;
position: fixed;
transform: translate(var(--state-x), var(--state-y));
}
This gives you:
- movement
- color change
- last key display
- all reactive
- all declarative
- zero JS logic
⭐ Why State.js + Keys.js Works So Well
Because they follow the same philosophy:
Top comments (0)