Text Scramble

Text Scramble component is used to create a text animation effect.

Basic Text Scramble

Loading...

Text Scramble on Hover

Loading...

Text Scramble with Custom Chars

Loading...

Usage Guide

Install the clsx and tailwind-merge packages:

npm install clsx tw-merge

Next, add cn utility function in your project:

import { twMerge } from "tailwind-merge";
import { clsx, type ClassValue } from "clsx";

export function cn(...inputs: ClassValue[]) {
    return twMerge(clsx(inputs));
}

Copy and paste the following component source.

"use client";

import { cn } from "@/lib/utils";
import React, { useState, useEffect, useCallback } from "react";

interface PropType {
    children: string;
    speed?: number;
    duration?: number;
    trigger?: boolean;
    className?: string;
    characterSet?: string;
    as?: React.ElementType;
    onScrambleEnd?: () => void;
}

const defaultCharacterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

export default function TextScramble({
    children = "Hello, World!",
    speed = 50,
    duration = 3,
    trigger = true,
    className = "",
    characterSet = defaultCharacterSet,
    as: Component = "span",
    onScrambleEnd
}: PropType) {
    const [scrambledText, setScrambledText] = useState(children);

    const scrambleText = useCallback(() => {
        let currentIndex = 0;
        const endTime = Date.now() + duration * 1000;

        const scrambleInterval = setInterval(() => {
            if (Date.now() > endTime) {
                clearInterval(scrambleInterval);
                setScrambledText(children);
                onScrambleEnd && onScrambleEnd();
                return;
            }

            const scrambled = children
                .split("")
                .map((char, index) => {
                    if (char === " ") {
                        return " ";
                    }
                    return index < currentIndex
                        ? char
                        : characterSet[Math.floor(Math.random() * characterSet.length)];
                })
                .join("");

            setScrambledText(scrambled);
            currentIndex = Math.min(currentIndex + 1, children.length);
        }, speed);

        return () => clearInterval(scrambleInterval);
    }, [children, duration, speed, characterSet, onScrambleEnd]);

    useEffect(() => {
        if (trigger) {
            const cleanup = scrambleText();
            return cleanup;
        } else {
            setScrambledText(children);
        }
    }, [trigger, scrambleText, children]);

    return <Component className={cn("font-mono", className)}>{scrambledText}</Component>;
}

Props

PropTypeDescriptionDefault
childrenstringThe text to display"Hello, World!"
durationnumberDuration of the scrambling animation (s).3
speednumberThe speed at which scrambling happens (ms).50
triggerbooleanTrigger the animation.true
characterSetstringCustom characters used for scrambling.[A-Za-z0-9]
classNamestringAdditional class names for styling._
asstringHTML tag name to wrap the text inside_
onScrambleEndfunctionFunction to run after the scrambling ends_