Text Scramble Animation
Create engaging text animations with a scramble effect that reveals the text on hover.
Text Scramble
Hello, World!
Customizable
Hover Over Me
tsx
1import React from 'react';
2import TextScramble from '@/components/ui/text-scramble';
3
4const ComponentPreview: React.FC = () => {
5 return (
6 <div className="flex h-9/12 items-center justify-center bg-gradient-to-br from-slate-900 to-slate-700">
7 <div className="grid grid-cols-1 gap-8 text-center">
8 <h1 className="mb-8 text-4xl font-bold text-white">
9 Text Scramble
10 </h1>
11
12 <TextScramble speed={30}>
13 Hello, World!
14 </TextScramble>
15
16 <TextScramble
17 blur="lg"
18 bgColor="purple-500"
19 bgOpacity={20}
20 speed={70}
21 scrambleChars="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
22 >
23 Customizable
24 </TextScramble>
25
26 <TextScramble
27 blur="sm"
28 bgOpacity={5}
29 className="rounded-full px-8"
30 >
31 Hover Over Me
32 </TextScramble>
33 </div>
34 </div>
35 );
36};
37
38export { ComponentPreview };Installation
Start by installing the required dependencies:
tsx
1No you don't need to install anything for this component :)Then, copy the following component code into your project:
components/ui/text-scramble.tsx
1'use client'
2import React, { useState, useEffect, useRef } from 'react';
3
4const useTextScramble = (text: string, speed = 50, scrambleChars = '!<>-_\\/[]{}—=+*^?#________') => {
5 const [currentText, setCurrentText] = useState(text);
6 const intervalRef = useRef<number | null>(null);
7
8 const scramble = () => {
9 let iteration = 0;
10
11 if (intervalRef.current) {
12 clearInterval(intervalRef.current);
13 }
14
15 intervalRef.current = window.setInterval(() => {
16 setCurrentText(
17 text
18 .split('')
19 .map((_, index) => {
20 if (index < iteration) {
21 return text[index];
22 }
23 return scrambleChars[Math.floor(Math.random() * scrambleChars.length)];
24 })
25 .join('')
26 );
27
28 if (iteration >= text.length) {
29 if (intervalRef.current) {
30 clearInterval(intervalRef.current);
31 }
32 }
33
34
35 iteration += 1 / 3;
36 }, speed);
37 };
38
39 const reset = () => {
40 if (intervalRef.current) {
41 clearInterval(intervalRef.current);
42 }
43 setCurrentText(text);
44 };
45
46 return { currentText, scramble, reset };
47};
48
49interface TextScrambleProps {
50 children: string;
51 className?: string;
52 blur?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';
53 bgColor?: string;
54 bgOpacity?: number;
55 speed?: number;
56 scrambleChars?: string;
57}
58
59const TextScramble: React.FC<TextScrambleProps> = ({
60 children,
61 className = '',
62 blur = 'md',
63 bgColor = 'white',
64 bgOpacity = 10,
65 speed = 50,
66 scrambleChars,
67}) => {
68 const { currentText, scramble, reset } = useTextScramble(children, speed, scrambleChars);
69
70 const blurClasses = {
71 sm: 'backdrop-blur-sm',
72 md: 'backdrop-blur-md',
73 lg: 'backdrop-blur-lg',
74 xl: 'backdrop-blur-xl',
75 '2xl': 'backdrop-blur-2xl',
76 '3xl': 'backdrop-blur-3xl',
77 };
78
79 const backgroundClass = `bg-${bgColor}/${bgOpacity}`;
80
81 return (
82 <div
83 onMouseEnter={scramble}
84 onMouseLeave={reset}
85 className={`relative inline-block overflow-hidden rounded-lg p-4 ${blurClasses[blur]} ${backgroundClass} border border-white/20 shadow-lg ${className}`}
86 >
87 <div className="relative z-10 font-mono text-white">{currentText}</div>
88 <div className="absolute inset-0 z-0 bg-gradient-to-br from-white/10 to-transparent"></div>
89 </div>
90 );
91};
92
93export default TextScramble;