
slot-text is a dependency-free JavaScript utility that creates rolling text animations where each character slides and rotates independently into place.
You can use the library to animate text transitions on copy-to-copied buttons, status messages, numeric counters, or any short label that changes dynamically.
Features:
- Zero runtime dependencies and a bundle footprint under 2 KB gzipped.
- Per-character roll animation with independent direction, stagger, and easing.
- Spam-safe flash mode that auto-reverts text after a configurable delay.
- Built-in chromatic color helper for rainbow per-character effects.
- Respects the host element’s font, including proportional and italic typefaces.
- Skips identical characters to avoid unnecessary motion.
- Interrupt control lets you either cut off or queue pending animation calls.
- Framework-specific wrappers for React, Vue, Solid, and Svelte.
How To Use It:
Installation
Install the package from npm.
npm install slot-text
Import the stylesheet once in your application entry file or component tree.
import "slot-text/style.css";
Basic Usage
Create a target element in your HTML.
<button id="publish-label" type="button">Publish</button>
Attach slotText() to the element and change the label when the user performs an action.
import "slot-text/style.css";
import { slotText, chromatic } from "slot-text";
const publishButton = document.querySelector("#publish-label");
// Create the animated label controller.
const publishLabel = slotText(publishButton, "Publish");
// Roll in a temporary success label with a color sweep.
publishButton.addEventListener("click", function () {
publishLabel.flash("Published", {
enter: {
color: chromatic()
}
});
});
React Usage
A React button can bind the visible label to component state. Import the CSS once and pass the animated text through the SlotText component.
import "slot-text/style.css";
import { useState } from "react";
import { SlotText } from "slot-text/react";
import { chromatic } from "slot-text";
export function ExportButton() {
const [exported, setExported] = useState(false);
return (
<button
type="button"
aria-label={exported ? "Report exported" : "Export report"}
onClick={() => setExported(true)}
>
<SlotText
text={exported ? "Exported" : "Export"}
options={{
direction: exported ? "up" : "down",
color: exported ? chromatic() : undefined
}}
/>
</button>
);
}
Vue Usage
A Vue component can render animated text from reactive state. Import the component and pass a normal options object.
<script setup lang="ts">
import "slot-text/style.css";
import { ref } from "vue";
import { SlotText } from "slot-text/vue";
const approved = ref(false);
</script>
<template>
<button
type="button"
-aria-label="approved ? 'Invoice approved' : 'Approve invoice'"
@click="approved = true"
>
<SlotText
-text="approved ? 'Approved' : 'Approve'"
-options="{ direction: approved ? 'up' : 'down' }"
/>
</button>
</template>
Solid Usage
A Solid component can attach the action to a span inside a button. Keep the accessible label on the button because the visual text changes during the animation.
import "slot-text/style.css";
import { createSignal } from "solid-js";
import { slotText } from "slot-text/solid";
export function InviteButton() {
const [label, setLabel] = createSignal("Invite");
return (
<button
type="button"
aria-label={label()}
onClick={() => setLabel("Invited")}
>
<span
use:slotText={{
text: label(),
options: { direction: "up" }
}}
/>
</button>
);
}
Svelte Usage
A Svelte button can use the action form for local UI state. The animated span receives the label and options object from component variables.
<script lang="ts">
import "slot-text/style.css";
import { slotText } from "slot-text/svelte";
let status = "Follow";
</script>
<button
type="button"
aria-label={status}
on:click={() => status = "Following"}
>
<span
use:slotText={{
text: status,
options: { direction: "up" }
}}
></span>
</button>
Configuration Options
direction("up" | "down"): Sets the vertical roll direction. The default value is"down".stagger(number): Sets the delay between character animations in milliseconds. The default value is45.duration(number): Sets the animation time for each character in milliseconds. The default value is300.exitOffset(number): Sets the delay before the previous character exits in milliseconds. The default value is50.easing(string): Sets the CSS easing function for the roll transition. The default value is a spring-style cubic-bezier curve.bounce(number): Sets the overshoot amount used by the animation. The default value is0.6.color(string | function): Sets a temporary text color for entering characters. A function receives the character index and total character count.colorFade(number): Sets the time in milliseconds for the animated color to fade back to the base text color. The default value is280.skipUnchanged(boolean): Keeps identical characters from rolling again. The default value istrue.interrupt(boolean): Controls behavior during an active animation.truestarts the latest animation immediately.falsewaits for the current roll to finish and drops duplicate pending text.
API Methods
import {
slotText,
buildSlotText,
animateSlotText,
clearSlotText,
chromatic
} from "slot-text";
const statusElement = document.querySelector("#payment-status");
// Create an animated text controller for one DOM element.
const paymentLabel = slotText(statusElement, "Pending", {
direction: "down"
});
// Roll to a new label and keep that value.
paymentLabel.set("Paid", {
direction: "up",
duration: 240
});
// Roll to a temporary label and return to the previous value.
paymentLabel.flash("Saved", {
revertAfter: 1400,
enter: {
direction: "up",
color: chromatic()
},
exit: {
direction: "down"
}
});
// Remove timers and restore the current text value.
paymentLabel.destroy();
// Build the per-character DOM structure directly.
buildSlotText(statusElement, "Ready");
// Animate a DOM element directly without the higher-level controller.
animateSlotText(statusElement, "Processing", {
direction: "up",
stagger: 35
});
// Clear the slot-text DOM structure and leave fallback text.
clearSlotText(statusElement, "Idle");
// Create a per-character hue sweep for the color option.
const rainbowText = chromatic({
from: 20,
spread: 280,
saturation: 90,
lightness: 58
});
Alternatives:
- Apply Smooth Animations to Text Using Data Attributes
- Animate Numbers With A Rolling Effect – number-flip
- Animate Text To Another With A Typing Effect – TypedText.js
- Text Shuffle Animation In Pure JavaScript – shuffle-text.js
- Create Handwritten SVG Text Animations in JavaScript
- 10 Best Typewriter Text Animation JavaScript Libraries







