Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Circular Text for React

Text set around a ring that turns slowly and speeds up under the pointer. For React with Base UI, when a badge, a seal or a scroll cue should turn on the page.

Framework

Circular Text sets a line of text around a ring that turns slowly, like a stamp or a seal, with anything you like still in its middle: an arrow, a logo, a star. The ring is sized from the text, so the characters never crowd or gap, and the pointer over it can speed it up, slow it down or stop it.

Use it for a "scroll to explore" cue, a badge on a hero, or a seal on a pricing card. For text that follows any curve or path instead of a circle, use Curved Loop; for a spiral, Spiral Text. It's CSS only: each character is rotated to its place and the ring turned by a keyframe animation the install adds to your stylesheet, with no animation library. With reduced motion the ring holds still.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import { CircularText } from "@/components/ui/circular-text";
<CircularText text="Scroll to explore • Scroll to explore • ">
  <ArrowDownIcon aria-hidden="true" />
</CircularText>

Demos

Hover

hover is what the pointer over the ring does: fast, the default, spins it four times as fast, slow halves its speed, pause stops it and none leaves it be. The speed changes from wherever the ring is, never jumping back to the start.

Preview width

Seal

duration is one turn, 20 seconds by default. The ring takes its size from the text and the font size; --circular-text-spacing sets the room each character takes, here a little more for bold capitals on a badge.

Preview width

Accessibility

Screen readers read the text once, in order, from a visually hidden copy, never the rotated characters. What sits in the middle is yours: give an icon aria-hidden="true" when the text already says what it means. With reduced motion the ring holds still.

FAQ

How big is the ring?

As big as the text needs: each character takes --circular-text-spacing, 0.75em by default, around the ring, so a longer text or a larger font makes a larger ring. Set the font size, or the spacing, to size it.

Why should the text end with a space or a separator?

The end of the text meets its start on the ring. A trailing space or • keeps the last word from running into the first; repeating a short phrase twice fills a ring evenly.

Why doesn't the ring jump when the speed changes?

The extra speed is a second spin inside the ring that only runs while the pointer is over it. Its turn adds to the ring's (or takes from it, for slow), so the ring carries on from where it is.

What can go in the middle?

Anything, as children: an icon, a logo, a short label or a number. It stays still while the ring turns around it.

What happens on a touch screen?

The ring turns at its own speed; the hover speeds only apply where there's a pointer that hovers.

What happens with reduced motion?

The ring holds still, with every character in its place.

API Reference

CircularText

<span> data-slot="circular-text"

PropType
textstring

The text around the ring; end it with a space or a separator (•) so the seam reads.

children?ReactNode

What sits still in the middle of the ring, such as an icon.

duration?number

One turn of the ring, in milliseconds. @default 20000.

Default
20_000
hover?"fast" | "slow" | "pause" | "none"

What the pointer over the ring does: spins it four times as fast, half as fast, stops it, or nothing.

Type
"fast" | "slow" | "pause" | "none"
Default
"fast"
render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Merged with the part's classes.

CSS variableType
--circular-text-countstring
--circular-text-durationstring

One turn of the ring (20s).

--circular-text-indexstring
--circular-text-spacingstring

The space each character takes around the ring (0.75em).

All 97 text effects