Spinning Text
Text arranged in a circle with each character positioned via trigonometry. The container rotates continuously.
Use and inspectUse this when the motion supports the surrounding content. Connect callbacks and state to your app, keep the reset preview as a local demonstration, and add a reduced-motion fallback for movement or looping. The preview is synthetic; it does not call a backend.Next: inspect the source below and replace the demo inputs with your own data.
Spinning TextText arranged in a circle with each character positioned via trigonometry. The container rotates continuously.
"use client";
import { motion } from "framer-motion";
type SpinningTextProps = {
text: string;
radius?: number;
duration?: number;
fontSize?: number;
};
export function SpinningText({ text, radius = 52, duration = 8, fontSize = 12 }: SpinningTextProps) {
const chars = text.split("");
const angleStep = 360 / chars.length;
const size = radius * 2 + fontSize * 2;
return (
<div
className="mp-spinning-text-container"
style={{ width: size, height: size, position: "relative" }}
>
<motion.div
style={{
width: "100%",
height: "100%",
position: "absolute",
top: 0,
left: 0,
}}
animate={{ rotate: 360 }}
transition={{ duration, repeat: Infinity, ease: "linear" }}
>
{chars.map((char, i) => {
const angle = i * angleStep;
const rad = (angle * Math.PI) / 180;
const x = size / 2 + radius * Math.sin(rad) - fontSize / 2;
const y = size / 2 - radius * Math.cos(rad) - fontSize / 2;
return (
<span
key={i}
className="mp-spinning-text-char"
style={{
position: "absolute",
left: x,
top: y,
fontSize: fontSize,
transform: "rotate(" + angle + "deg)",
transformOrigin: "50% 50%",
}}
>
{char}
</span>
);
})}
</motion.div>
</div>
);
}Install
npm install framer-motionProps
| Prop | Type | Default | Description |
|---|---|---|---|
| textrequired | string | — | Text to display in a circle |
| radius | number | 52 | Circle radius in px |
| duration | number | 8 | Full rotation duration in seconds |
| fontSize | number | 12 | Character font size in px |