Introducing Motion-Primitives Pro - Advanced components and templates to help you build a website that stands out.

Text Scramble

Text animation that transforms text by randomly cycling through characters before settling on the final content, creating an engaging cryptographic effect.

Examples

Text Scramble Basic

Text Scramble

Text Scramble with custom trigger

Text Scramble with custom character and duration

Generating the interface...

Code

'use client';
import { type JSX, useEffect, useState } from 'react';
import { motion, MotionProps } from 'motion/react';

type TextScrambleProps = {
  children: string;
  duration?: number;
  speed?: number;
  characterSet?: string;
  as?: React.ElementType;
  className?: string;
  trigger?: boolean;
  onScrambleComplete?: () => void;
} & MotionProps;

const defaultChars =
  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

export function TextScramble({
  children,
  duration = 0.8,
  speed = 0.04,
  characterSet = defaultChars,
  className,
  as: Component = 'p',
  trigger = true,
  onScrambleComplete,
  ...props
}: TextScrambleProps) {
  const MotionComponent = motion.create(
    Component as keyof JSX.IntrinsicElements
  );
  const [displayText, setDisplayText] = useState(children);
  const [isAnimating, setIsAnimating] = useState(false);
  const text = children;

  const scramble = async () => {
    if (isAnimating) return;
    setIsAnimating(true);

    const steps = duration / speed;
    let step = 0;

    const interval = setInterval(() => {
      let scrambled = '';
      const progress = step / steps;

      for (let i = 0; i < text.length; i++) {
        if (text[i] === ' ') {
          scrambled += ' ';
          continue;
        }

        if (progress * text.length > i) {
          scrambled += text[i];
        } else {
          scrambled +=
            characterSet[Math.floor(Math.random() * characterSet.length)];
        }
      }

      setDisplayText(scrambled);
      step++;

      if (step > steps) {
        clearInterval(interval);
        setDisplayText(text);
        setIsAnimating(false);
        onScrambleComplete?.();
      }
    }, speed * 1000);
  };

  useEffect(() => {
    if (!trigger) return;

    scramble();
  }, [trigger]);

  return (
    <MotionComponent className={className} {...props}>
      {displayText}
    </MotionComponent>
  );
}

Component API

TextScramble

PropTypeDefaultDescription
childrenstringThe text content to be animated.
askeyof JSX.IntrinsicElements'p'The HTML tag to render, defaults to paragraph.
durationnumber0.8Duration of the effect.
speednumber0.04Speed of the effect.
characterSetstringABCDEF...z0123456789Set of characters for the scramble effect
classNamestringundefinedOptional CSS class for styling the component.
triggerbooleanundefinedControls whether the animation should be triggered.
onScrambleComplete() => voidundefinedCallback function when the animation completes.