Spinning Text
Easily animate text circularly. Customize the animation with variants and transitions.
Examples
Basic Usage
pre-order • pre-order • pre-order •
Custom Transition
motion-primitives • motion-primitives •
Custom Variants
pre-order • pre-order • pre-order •
Code
'use client';
import { cn } from '@/lib/utils';
import { motion, Transition, Variants } from 'framer-motion';
import React, { CSSProperties } from 'react';
type SpinningTextProps = {
children: string;
style?: CSSProperties;
duration?: number;
className?: string;
reverse?: boolean;
fontSize?: number;
radius?: number;
transition?: Transition;
variants?: {
container?: Variants;
item?: Variants;
};
};
const BASE_TRANSITION = {
repeat: Infinity,
ease: 'linear',
};
const BASE_ITEM_VARIANTS = {
hidden: {
opacity: 1,
},
visible: {
opacity: 1,
},
};
export function SpinningText({
children,
duration = 10,
style,
className,
reverse = false,
fontSize = 1,
radius = 5,
transition,
variants,
}: SpinningTextProps) {
const letters = children.split('');
const totalLetters = letters.length;
const finalTransition = {
...BASE_TRANSITION,
...transition,
duration: (transition as { duration?: number })?.duration ?? duration,
};
const containerVariants = {
visible: { rotate: reverse ? -360 : 360 },
...variants?.container,
};
const itemVariants = {
...BASE_ITEM_VARIANTS,
...variants?.item,
};
return (
<motion.div
className={cn('relative', className)}
style={{
...style,
}}
initial='hidden'
animate='visible'
variants={containerVariants}
transition={finalTransition}
>
{letters.map((letter, index) => (
<motion.span
aria-hidden='true'
key={`${index}-${letter}`}
variants={itemVariants}
className='absolute left-1/2 top-1/2 inline-block'
style={
{
'--index': index,
'--total': totalLetters,
'--font-size': fontSize,
'--radius': radius,
fontSize: `calc(var(--font-size, 2) * 1rem)`,
transform: `
translate(-50%, -50%)
rotate(calc(360deg / var(--total) * var(--index)))
translateY(calc(var(--radius, 5) * -1ch))
`,
transformOrigin: 'center',
} as React.CSSProperties
}
>
{letter}
</motion.span>
))}
<span className='sr-only'>{children}</span>
</motion.div>
);
}
Please add:
Component API
SpinningText
Prop | Type | Default | Description |
---|---|---|---|
children | ReactElement | The text content to be animated in a circular motion. | |
style | CSSProperties | {} | Custom styles for the text container. |
duration | number | 10 | The duration of the full circular rotation animation. |
className | string | A custom class name for the text container. | |
reverse | boolean | false | Determines if the animation should rotate in reverse. |
fontSize | number | 1 | The font size of the text being animated in rem. |
radius | number | 5 | The radius of the circular path for the text animation. |
transition | Transition | Custom transition effects for the animation. | |
variants | { container?: Variants; item?: Variants; } | Variants for container and item animations. |
Credit
Initiated by @ibtihelbs