motion-primitives
components
ui
animation
motion

text-shimmer-wave

Shimmer wave effect on text.

3d
animated
effect
form
gradient
positioning
special
text
transform
transition
View Docs

Source Code

Files
text-shimmer-wave.tsx
1'use client';
2import { type JSX } from 'react';
3import { motion, Transition } from 'motion/react';
4import { cn } from '@/lib/utils';
5
6export type TextShimmerWaveProps = {
7  children: string;
8  as?: React.ElementType;
9  className?: string;
10  duration?: number;
11  zDistance?: number;
12  xDistance?: number;
13  yDistance?: number;
14  spread?: number;
15  scaleDistance?: number;
16  rotateYDistance?: number;
17  transition?: Transition;
18};
19
20export function TextShimmerWave({
21  children,
22  as: Component = 'p',
23  className,
24  duration = 1,
25  zDistance = 10,
26  xDistance = 2,
27  yDistance = -2,
28  spread = 1,
29  scaleDistance = 1.1,
30  rotateYDistance = 10,
31  transition,
32}: TextShimmerWaveProps) {
33  const MotionComponent = motion.create(
34    Component as keyof JSX.IntrinsicElements
35  );
36
37  return (
38    <MotionComponent
39      className={cn(
40        'relative inline-block [perspective:500px]',
41        '[--base-color:#a1a1aa] [--base-gradient-color:#000]',
42        'dark:[--base-color:#71717a] dark:[--base-gradient-color:#ffffff]',
43        className
44      )}
45      style={{ color: 'var(--base-color)' }}
46    >
47      {children.split('').map((char, i) => {
48        const delay = (i * duration * (1 / spread)) / children.length;
49
50        return (
51          <motion.span
52            key={i}
53            className={cn(
54              'inline-block whitespace-pre [transform-style:preserve-3d]'
55            )}
56            initial={{
57              translateZ: 0,
58              scale: 1,
59              rotateY: 0,
60              color: 'var(--base-color)',
61            }}
62            animate={{
63              translateZ: [0, zDistance, 0],
64              translateX: [0, xDistance, 0],
65              translateY: [0, yDistance, 0],
66              scale: [1, scaleDistance, 1],
67              rotateY: [0, rotateYDistance, 0],
68              color: [
69                'var(--base-color)',
70                'var(--base-gradient-color)',
71                'var(--base-color)',
72              ],
73            }}
74            transition={{
75              duration: duration,
76              repeat: Infinity,
77              repeatDelay: (children.length * 0.05) / spread,
78              delay,
79              ease: 'easeInOut',
80              ...transition,
81            }}
82          >
83            {char}
84          </motion.span>
85        );
86      })}
87    </MotionComponent>
88  );
89}
90