Text Effects
TextOrbit
Text runs round a circle and slowly turns, like a badge stamp. Anything in children sits still in the middle.
Download
- React
- Tailwind CSS v4
- motion
components/ui/text-orbit.tsx
"use client";
import { useId, type ReactNode } from "react";
import { motion, useReducedMotion } from "motion/react";
type TextOrbitProps = {
/** Text round the circle. End it with a separator (" • ") so the join looks even. */
text: string;
/** Sits still in the middle. */
children?: ReactNode;
/** Width and height, in pixels. */
size?: number;
/** Seconds per full turn. */
duration?: number;
className?: string;
};
/* TextOrbit: text runs round a circle and slowly turns, like a badge stamp. Anything in children sits still in the middle. */
export function TextOrbit({ text, children, size = 160, duration = 14, className = "" }: TextOrbitProps) {
const reduce = useReducedMotion();
const pathId = `to${useId().replace(/[^a-zA-Z0-9]/g, "")}`;
const r = 40; // inside a 100 x 100 box
return (
<div className={`relative inline-grid place-items-center ${className}`} style={{ width: size, height: size }}>
<span className="sr-only">{text}</span>
<motion.svg
aria-hidden
viewBox="0 0 100 100"
className="absolute inset-0 h-full w-full overflow-visible"
animate={reduce ? undefined : { rotate: 360 }}
transition={{ duration, repeat: Infinity, ease: "linear" }}
>
<defs>
<path id={pathId} d={`M 50,50 m -${r},0 a ${r},${r} 0 1,1 ${r * 2},0 a ${r},${r} 0 1,1 -${r * 2},0`} />
</defs>
<text fill="currentColor" fontSize="9">
{/* Stretch the spacing so the text closes the circle exactly. */}
<textPath href={`#${pathId}`} textLength={2 * Math.PI * r} lengthAdjust="spacing">
{text}
</textPath>
</text>
</motion.svg>
{children && <div className="relative">{children}</div>}
</div>
);
}
1. Install the dependency.
npm i motion2. Paste the Code tab into
components/ui/text-orbit.tsx. The styles are Tailwind CSS v4 classes.3. Use it. This is the preview above:
app/text-orbit-demo.tsx
import { TextOrbit } from "@/components/ui/text-orbit"; export default function TextOrbitExample() { return ( <div className="grid h-full place-items-center bg-[#0f1a17]"> <TextOrbit text="MADE WITH BLACKYDEVELOPER • MOTION FIRST • " size={180} className="font-mono font-semibold text-[#34f5c5]"> <span className="grid size-16 place-items-center rounded-full bg-[#34f5c5] text-2xl text-[#0f1a17]">✦</span> </TextOrbit> </div> ); }
Props
| Name | Type | Default | What it does |
|---|---|---|---|
| text | string | — | Text round the circle. End it with a separator so the join looks even. |
| children | ReactNode | — | Sits still in the middle. |
| size | number | 160 | Width and height, in pixels. |
| duration | number | 14 | Seconds per full turn. |
| className | string | "" | Font and colour (text uses currentColor). |