@tasul/shuffle-text-react
v1.0.0
Published
React component and hook for @tasul/shuffle-text
Maintainers
Readme
@tasul/shuffle-text-react
React bindings for @tasul/shuffle-text —
a text-switching / morphing effect that cycles an element's text through a list
of strings, one character at a time.
Gives you a declarative <ShuffleText> component and a useShuffleText
hook for imperative control. The wrapper handles instance creation and cleanup
on unmount, so you don't manage timers yourself.

Install
npm i @tasul/shuffle-text-reactreact (>= 17) is a peer dependency — it uses the one already in your app.
Component (declarative)
The simplest path. Hand it a textArray and it renders + animates a container
element. Set isAuto to loop automatically.
import { ShuffleText } from '@tasul/shuffle-text-react';
const WORDS = ['Hello', 'Yo!', '¡Hola!', 'Salut', '안녕하세요', 'こんにちは'];
export function Hero() {
return <ShuffleText as="h1" textArray={WORDS} isAuto isReplacedRandomly />;
}Props
Core options (each is a prop):
| Prop | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| textArray | string[] | — (required) | Strings to cycle through. Use 2+ for a visible morph. |
| isAuto | boolean | false | Start the auto loop on mount. |
| isReplacedRandomly | boolean | false | Swap characters in random order instead of left-to-right. |
| isDisorderedArray | boolean | false | Shuffle the order of the strings once, on mount. |
| stayTime | number | 1500 | Pause (ms) on a finished word before the next (auto loop). |
| replaceTime | number | 50 | Time (ms) between each character swap. Lower = faster. |
Container props (React-specific):
| Prop | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| as | keyof JSX.IntrinsicElements | 'div' | Which element/tag to render as. |
| className | string | — | Class on the container (style the morph here). |
| style | CSSProperties | — | Inline styles on the container. |
<ShuffleText
as="span"
className="headline"
textArray={WORDS}
isAuto
stayTime={2000}
replaceTime={40}
/>Style the per-character spans via the container class:
.headline span { display: inline-block; transition: opacity 0.15s; }Hook (imperative)
Want to trigger the morph yourself — on click, hover, scroll-into-view? Use the
hook. It hands you a ref to attach to your own element plus the controls.
import { useShuffleText } from '@tasul/shuffle-text-react';
function MenuButton() {
const { ref, play, playAuto, clear } = useShuffleText<HTMLSpanElement>({
textArray: ['Menu', 'Close'],
});
return (
<button onClick={play}>
<span ref={ref} />
</button>
);
}What the hook returns
| Field | Type | Description |
| :--- | :--- | :--- |
| ref | RefObject<T> | Attach to the element you want to animate. |
| play | () => void | Morph once to the next string. |
| playAuto | () => void | Start the auto loop. |
| clear | () => void | Stop the loop/timers (also runs automatically on unmount). |
useShuffleText<T>() is generic over the element type — default HTMLDivElement.
Recipes
Play when scrolled into view:
function OnView() {
const { ref, playAuto } = useShuffleText<HTMLDivElement>({ textArray: WORDS });
useEffect(() => {
const io = new IntersectionObserver(([e]) => e.isIntersecting && playAuto());
if (ref.current) io.observe(ref.current);
return () => io.disconnect();
}, []);
return <div ref={ref} />;
}Notes & gotchas
Options are read once, on mount. Changing
textArray(or any prop) on an already-mounted component does not restart the morph. To reset it with new options, remount via a changing Reactkey:<ShuffleText key={lang} textArray={wordsFor(lang)} isAuto />The component is declarative; the hook is the imperative escape hatch. If you need
play()/playAuto()on demand, useuseShuffleText, not the component.SSR (Next.js / Remix): the effect runs only in the browser after mount, so nothing executes on the server. No
<ClientOnly>wrapper needed — the morph simply begins after hydration.textArrayneeds 2+ entries to morph; a single string just renders once.
License
MIT © tasul
