Circular Text
A flexible component for rendering text along a circular path with customizable styling and rotation.
1. Copy the component file
Create a new file called circular-text.jsx in
your reusable components folder (for example
/src/components/) and paste the following code
into it.
circular-text.jsx
import { memo } from "react";
import styles from "./circular-text.module.css";
const CircularText = (props) => {
const {
text,
radius,
addTrailingSpace = true,
rotate = false,
direction = "clockwise",
duration = 10 * 1000,
className,
style = null,
letterClassName,
letterStyle = null,
...restProps
} = props;
const _text = text.trim() + (addTrailingSpace ? " " : "");
const _radius = Math.max(0, radius);
const _duration = Math.min(Math.max(100, duration), 60 * 1000);
const getCoordinates = (angle, radius) => {
const radians = +((Math.PI / 180) * angle).toPrecision(4);
return {
x: +((Math.cos(radians) * radius).toFixed(0)),
y: +((Math.sin(radians) * radius).toFixed(0)),
};
};
return (
<span
{...restProps}
className={[
className,
styles["circular-text"],
rotate ? styles[`rotate-${direction}`] : "",
].join(" ")}
style={{
...style,
"--radius": `${_radius}px`,
"--duration": `${_duration}ms`,
}}
>
{[..._text].map((letter, letterIndex) => {
const angle = 360 / _text.length * letterIndex;
const { x, y } = getCoordinates(angle, _radius);
return (
<span
aria-hidden={true}
key={`letter-${letter}-${letterIndex}`}
className={letterClassName}
style={{
...letterStyle,
"--x": `${x}px`,
"--y": `${y}px`,
"--angle": `${angle}deg`,
}}
>
{letter === " " ? <> </> : letter}
</span>
);
})}
<span
className={styles["sr-only"]}
>
{text}
</span>
</span>
);
};
export default memo(CircularText); 2. Copy the CSS module file
In the same folder, create a file called circular-text.module.css and paste the following CSS.
circular-text.module.css
.circular-text {
position: relative;
width: calc(var(--radius) * 2);
height: calc(var(--radius) * 2);
animation-duration: var(--duration);
animation-timing-function: linear;
animation-iteration-count: infinite;
&.rotate-clockwise {
animation-name: circular-text-keyframes;
}
&.rotate-anti-clockwise {
animation-name: circular-text-keyframes;
animation-direction: reverse;
}
>span {
position: absolute;
top: 50%;
left: 50%;
transform-origin: 50% 50%;
transform:
translate(calc(-50% + var(--x)), calc(-50% + var(--y)))
rotate(var(--angle));
}
> .sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
animation: none;
}
}
@keyframes circular-text-keyframes {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
} 3. Use the component
Now you can import and use the component anywhere in your project.
circular-text-preview.jsx
import CircularText from "@/components/text-effects/circular-text/circular-text";
const CircularTextPreview = () => {
return (
<CircularText
text="CODE • DESIGN • SHIP •"
radius={80}
rotate={true}
/>
);
};
export default CircularTextPreview; Anti-Clockwise Direction
circular-text
import CircularText from "@/components/text-effects/circular-text/circular-text";
const CircularTextAntiClockwiseDirectionPreview = () => {
return (
<CircularText
text="CODE • DESIGN • SHIP •"
radius={85}
rotate={true}
direction="anti-clockwise"
/>
);
};
export default CircularTextAntiClockwiseDirectionPreview; Duration
circular-text
import CircularText from "@/components/text-effects/circular-text/circular-text";
const CircularTextDurationPreview = () => {
return (
<CircularText
text="CODE • DESIGN • SHIP •"
radius={85}
rotate={true}
duration={5000}
/>
);
};
export default CircularTextDurationPreview; Props
Configure the component with the following props:
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| text | string | Yes | — | The text content to render around the circle. |
| radius | number | Yes | — | Radius of the circle in pixels (px) used to position the letters. |
| addTrailingSpace | boolean | No | true | Adds a trailing space after the text to improve spacing when looping around the circle. |
| rotate | boolean | No | false | Enables continuous rotation animation of the circular text. |
| direction | "clockwise" | "anti-clockwise" | No | "clockwise" | Controls the rotation direction of the text around the circle. |
| duration | number | No | 10000 | Duration of one full rotation in milliseconds (range: 100 – 60000). |
| className | string | No | — | Optional class name applied to the root circular text container. |
| style | React.CSSProperties | No | — | Inline styles applied to the root container. |
| letterClassName | string | No | — | Class name applied to each individual letter element. |
| letterStyle | React.CSSProperties | No | — | Inline styles applied to each individual letter. |