flash() rolls up, then rolls back on its own.
Text that rolls into place
A tiny, dependency-free roll animation for buttons, counters and status labels. By character or whole word. The headline above is running on it.
Every segment is its own slot.
The text is split into characters or words. Each one sits in a clipped cell. On a change, the old face slides out of its cell while the new one slides in behind it, staggered left to right. Nothing here is a video. Slow it down and watch.
Four places it belongs.
Every cell is live. Click one.
direction: "up" for state that moves forward.
skipUnchanged rolls only the digits that moved.
rollBy: "word" keeps kerning and ligatures intact.
Small enough to forget it is there.
Zero dependencies
One module, about 1 kB of CSS. Transforms only, no canvas, no timeline library.
Character or word
Roll by user-perceived character, including emoji, or keep whole words together.
Spam-safe
Rapid calls interrupt cleanly or queue the latest target. No stacked rolls, no stuck faces.
Four adapters
React, Vue, Solid and Svelte as subpath imports. Optional peers, nothing forced.
Three lines from static to rolling.
1. Install
2. Import the stylesheet once
It is the cell clipping and nothing else. Skip it and the text still swaps, it just does not roll.
3. Wrap a label
Pass an element and its starting text. Call set whenever the text
changes.
import { slotText } from "slot-text"; import "slot-text/style.css"; const label = slotText(el, "Save"); label.set("Changes saved", { rollBy: "word" });
import { SlotText } from "slot-text/react"; import "slot-text/style.css"; <SlotText text="Changes saved" options={{ rollBy: "word" }} />
import { SlotText } from "slot-text/vue"; import "slot-text/style.css"; <SlotText text="Changes saved" :options="{ rollBy: 'word' }" />
import { slotText } from "slot-text/solid"; import "slot-text/style.css"; <span use:slotText={{ text: "Changes saved", options: { rollBy: "word" }, }} />
import { slotText } from "slot-text/svelte"; import "slot-text/style.css"; <span use:slotText={{ text: "Changes saved", options: { rollBy: "word" }, }} ></span>