Launched best Saas Marketing template at cheap — Check out

Circular Text

Circular text animations create a circular text effect that continuously rotates. This engaging animation can be used to draw attention to important content or add visual interest to your design.

Installation

npm install framer-motion
pnpm install framer-motion
yarn add framer-motion
bun add framer-motion
'use client';import {  motion,  MotionValue,  Transition,  useAnimation,  useMotionValue,} from 'framer-motion';import { useEffect } from 'react';type CircularTextProps = {  text: string;  spinDuration?: number;  onHover?: 'slowDown' | 'speedUp' | 'pause' | 'goBonkers';  className?: string;};const getRotationTransition = (  duration: number,  from: number,  loop: boolean = true,) => ({  from,  to: from + 360,  ease: 'linear' as const,  duration,  type: 'tween' as const,  repeat: loop ? Infinity : 0,});const getTransition = (duration: number, from: number) => ({  rotate: getRotationTransition(duration, from),  scale: {    type: 'spring' as const,    damping: 20,    stiffness: 300,  },});export function CircularText({  text = 'Circular Text Animation • ',  spinDuration = 20,  onHover = 'speedUp',  className = '',}: Readonly<CircularTextProps>) {  const letters = Array.from(text);  const controls = useAnimation();  const rotation: MotionValue<number> = useMotionValue(0);  useEffect(() => {    const start = rotation.get();    controls.start({      rotate: start + 360,      scale: 1,      transition: getTransition(spinDuration, start),    });  }, [spinDuration, text, onHover, controls]);  const handleHoverStart = () => {    const start = rotation.get();    if (!onHover) return;    let transitionConfig: ReturnType<typeof getTransition> | Transition;    let scaleVal = 1;    switch (onHover) {      case 'slowDown':        transitionConfig = getTransition(spinDuration * 2, start);        break;      case 'speedUp':        transitionConfig = getTransition(spinDuration / 4, start);        break;      case 'pause':        transitionConfig = {          rotate: { type: 'spring', damping: 20, stiffness: 300 },          scale: { type: 'spring', damping: 20, stiffness: 300 },        };        break;      case 'goBonkers':        transitionConfig = getTransition(spinDuration / 20, start);        scaleVal = 0.8;        break;      default:        transitionConfig = getTransition(spinDuration, start);    }    controls.start({      rotate: start + 360,      scale: scaleVal,      transition: transitionConfig,    });  };  const handleHoverEnd = () => {    const start = rotation.get();    controls.start({      rotate: start + 360,      scale: 1,      transition: getTransition(spinDuration, start),    });  };  return (    <div className="flex min-h-[400px] items-center justify-center rounded-lg">      <motion.div        className={`relative m-0 mx-auto h-[200px] w-[200px] origin-center cursor-pointer rounded-full text-center font-black text-white ${className}`}        style={{ rotate: rotation }}        initial={{ rotate: 0 }}        animate={controls}        onMouseEnter={handleHoverStart}        onMouseLeave={handleHoverEnd}      >        {letters.map((letter, i) => {          const rotationDeg = (360 / letters.length) * i;          const factor = Math.PI / letters.length;          const x = factor * i;          const y = factor * i;          const transform = `rotateZ(${rotationDeg}deg) translate3d(${x}px, ${y}px, 0)`;          return (            <span              key={i}              className="absolute inset-0 inline-block text-2xl transition-all duration-500 ease-out"              style={{ transform, WebkitTransform: transform }}            >              {letter}            </span>          );        })}      </motion.div>    </div>  );}export default CircularText;

Usage

import { CircularText } from "@/components/mvpblocks/text-animations/circular-text";

export default function MyComponent() {
  return (
    <div className="flex items-center justify-center h-screen bg-black">
      <CircularText
        text="Circular Text Animation • "
        spinDuration={20}
        onHover="speedUp"
        className="text-white"
      />
    </div>
  );
}

API

Prop

Type

Features

  • 🎯 Smooth Animation: Continuous rotation with customizable speed
  • 🎨 Hover Effects: Multiple hover behaviors (slowDown, speedUp, pause, goBonkers)
  • 🎪 Customizable: Easy to style with CSS classes
  • 📱 Responsive: Works well on different screen sizes
  • Performance: Optimized with framer-motion

Examples

Speed Up on Hover

<CircularText
  text="Speed Up Effect • "
  spinDuration={15}
  onHover="speedUp"
/>

Pause on Hover

<CircularText
  text="Pause on Hover • "
  spinDuration={25}
  onHover="pause"
/>

Go Bonkers on Hover

<CircularText
  text="Go Bonkers! • "
  spinDuration={30}
  onHover="goBonkers"
/>