Circular Text <mv-circular-text>
Anel giratório de texto em volta de um ícone, logo ou avatar, traçado ao longo de um círculo SVG real para que a fonte mantenha o kerning e o loop se feche de forma uniforme; ao passar o mouse ou com o foco, o giro acelera, desacelera, para ou se inverte suavemente.
Como funciona
Anel giratório de texto em volta de um ícone, logotipo ou avatar, traçado ao longo de um círculo SVG real para que a fonte mantenha o kerning e o loop feche por igual; passar o mouse ou focar faz o giro acelerar, desacelerar, parar ou inverter com suavidade. Os leitores de tela ouvem o texto uma única vez, e o anel fica parado com movimento reduzido.
| Categoria | Texto animado |
|---|---|
| Tipo | Web Component (<mv-circular-text>) |
| Status | estável |
| Keywords | circular, spinning-text, badge, sticker, scroll-indicator, rotate, svg, accessible |
When to use
- A round badge or sticker needs text spinning around a logo, avatar or icon
- A hero corner needs a looping indicator such as 'scroll down' or 'available for work'
- A spinning link badge should pause while it is hovered or focused so it can be read
Avoid when
- The text is long or must be read quickly; ring text is hard to scan beyond a few words
- Several words should replace each other inline inside a sentence → use Word Rotate instead
Instalação
node scripts/add.mjs circular-text --out ./src/marvelousAgente de IA com o servidor MCP do Marvelous UI: install_components({ slugs: ["circular-text"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Arquivos copiados (dependências incluídas): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/i18n.js, core/motion.js, core/observe.js, components/circular-text/circular-text.js, components/circular-text/circular-text.css.
Uso
Marcação de referência, para usar como ponto de partida e personalizar com atributos, data-* e variáveis CSS:
<div style="display:flex;flex-wrap:wrap;gap:2.5rem;align-items:center;justify-content:center">
<a href="#circular-text" aria-label="Scroll to explore" style="color:inherit;text-decoration:none;border-radius:50%">
<mv-circular-text text="Scroll to explore • " hover="pause" duration="16000" style="font:600 .85rem/1 var(--mv-font-mono);text-transform:uppercase;letter-spacing:.08em">
<span data-center style="display:grid;place-items:center;width:3rem;height:3rem;border-radius:50%;background:var(--mv-fg);color:var(--mv-bg)">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M6 13l6 6 6-6"/></svg>
</span>
</mv-circular-text>
</a>
<mv-circular-text text="New • 2026 Edition • " repeat="2" hover="reverse" duration="12000" style="font:700 .95rem/1 var(--mv-font-display);text-transform:uppercase;letter-spacing:.12em;color:var(--mv-fg-on-accent);background:radial-gradient(circle at 30% 25%,color-mix(in oklch,var(--mv-accent),white 18%),var(--mv-accent) 60%);box-shadow:var(--mv-shadow-lg), inset 0 0 0 1px color-mix(in oklch, white 20%, transparent)">
<svg data-center width="34" height="34" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2.5l2.6 6.1 6.6.6-5 4.4 1.5 6.5L12 16.7l-5.7 3.4 1.5-6.5-5-4.4 6.6-.6z"/></svg>
</mv-circular-text>
<mv-circular-text text="Available for new projects • " hover="slow-down" direction="ccw" duration="22000" style="font:600 .8rem/1 var(--mv-font-sans);letter-spacing:.16em;text-transform:uppercase;color:var(--mv-fg-muted)">
<span data-center aria-hidden="true" style="display:grid;place-items:center;width:3.6rem;height:3.6rem;border-radius:50%;background:var(--mv-bg-muted);border:1px solid var(--mv-border);font:700 1.1rem/1 var(--mv-font-display);color:var(--mv-fg);position:relative">
AK
<span style="position:absolute;right:.1rem;bottom:.15rem;width:.7rem;height:.7rem;border-radius:50%;background:var(--mv-success);box-shadow:0 0 0 2px var(--mv-bg)"></span>
</span>
</mv-circular-text>
</div>API
Attributes
| Name | Tipo | Padrão | Descrição |
|---|---|---|---|
text | string | Ring text (otherwise the child text). A trailing separator (“ • ”) makes a clean loop; a space is added when there is none. | |
label | string | Replaces the screen reader text. By default it is the ring text, read once, with separators turned into commas. | |
repeat | number | 1 | Repeats the text around the ring (up to 12 times); screen readers still hear it once. |
duration | number (ms) | 20000 | Duration of one full turn. |
direction | cw | ccw | cw | Rotation direction. |
hover | speed-up | slow-down | pause | reverse | none | speed-up | Reaction to mouse hover and to keyboard focus, on the ring or on a wrapping link or button; the speed eases on a spring. Taps do not count as hover. |
paused | boolean | Stops the rotation. It also stops by itself off-screen, in hidden tabs and under reduced motion. |
Content structure
| Name | Descrição |
|---|---|
[data-center] | Centered element (icon, avatar, logo). The ring grows so it never overlaps it. |
CSS variables
| Name | Padrão | Descrição |
|---|---|---|
--mv-circular-text-radius | (auto, from the measured text) | Forced ring radius (to the middle of the letters); the spacing stretches or tightens to fill it. |
--mv-circular-text-spread | 1.05 | Spacing factor when the radius is automatic (1 = the font's natural spacing, 1.2 = 20% looser). |
--mv-circular-text-advance | 0.62em | Average width per character, used only while the text cannot be measured yet (hidden or not rendered). |
Accessibility
The ring is an aria-hidden SVG; a visually hidden copy gives screen readers the text once as a normal string, without repeats, with bullet separators read as commas (or the label attribute). Hover with a mouse or pen and keyboard focus (inside the badge or on a wrapping link or button) apply the hover reaction, so hover="pause" holds the text still to be read. The rotation also stops off-screen, in hidden tabs and under reduced motion, where the ring stays static and readable. The letters use currentColor, so forced colors apply. When the badge sits inside a link, give the link an explicit aria-label.