Word Rotate <mv-word-rotate>
Mot rotatif en ligne pour les phrases de hero (glissement, retournement 3D, flou ou fondu, lettre par lettre) dont la largeur s’ajuste en douceur pour que la phrase ne saute jamais. Accessible par défaut : les lecteurs d’écran entendent une seule phrase stable qui liste toutes les options, il s’arrête au survol et au focus d’un lien qui l’englobe, se met en pause hors écran et dans les onglets masqués, et reste sur un seul mot en mouvement réduit.
| Catégorie | Texte animé |
|---|---|
| Type | Web Component (<mv-word-rotate>) |
| Statut | stable |
| Keywords | rotating-text, flip-words, text-loop, hero, headline, inline, layout-animation, accessible |
When to use
- A hero headline should cycle one inline word, like Build for designers, developers or teams
- The rotating word should sit in a tinted pill whose width animates between words
- A sold or public page needs a rotating word that screen readers hear once, not on every change
- The word loop must be driven from script with next, previous or an index
Avoid when
- A standalone word should melt into the next with a gooey blur → use Morphing Text instead
- Whole phrases should be typed and deleted letter by letter → use Typewriter instead
Installation
node scripts/add.mjs word-rotate --out ./src/marvelousAgent IA avec le serveur MCP de Marvelous UI : install_components({ slugs: ["word-rotate"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Fichiers copiés (dépendances comprises) : tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, core/observe.js, components/word-rotate/word-rotate.js, components/word-rotate/word-rotate.css.
Utilisation
Démarrage rapide, le balisage minimal qui fonctionne :
<p>Build for <mv-word-rotate words="designers, developers, teams"></mv-word-rotate></p>Balisage de référence : partez de celui-ci et personnalisez-le avec les attributs, data-* et les variables CSS :
<div style="display:grid;gap:2rem;width:min(100%,46rem);margin-inline:auto;text-align:center">
<h2 style="margin:0;font:700 clamp(1.9rem,4.6vw,3.2rem)/1.15 var(--mv-font-display);letter-spacing:-.035em">
Build for
<mv-word-rotate data-variant="pill" words="designers, developers, teams" style="--mv-word-rotate-color:var(--mv-accent-fg)"></mv-word-rotate>
<br>without the all-nighters.
</h2>
<div style="display:grid;gap:.9rem;font-size:clamp(1.1rem,2.4vw,1.45rem);font-weight:600;letter-spacing:-.02em">
<p style="margin:0">Interfaces that feel <mv-word-rotate effect="flip" interval="2200" words="fast, reliable, elegant, accessible" colors="var(--mv-accent), var(--mv-info), var(--mv-success), var(--mv-warning)"></mv-word-rotate></p>
<p style="margin:0">From prototype to <mv-word-rotate effect="blur" interval="2400" conjunction="and" words="production, launch, growth" style="--mv-word-rotate-color:var(--mv-accent)"></mv-word-rotate></p>
<p style="margin:0;color:var(--mv-fg-muted)">Ships as <mv-word-rotate effect="slide" direction="down" interval="1800" words="HTML, React, Vue, Svelte, Astro" style="--mv-word-rotate-color:var(--mv-fg);font-family:var(--mv-font-mono)"></mv-word-rotate>, zero friction.</p>
<p style="margin:0;color:var(--mv-fg-muted)">Looks <mv-word-rotate effect="fade" interval="2000" words="crisp, smooth, clean" style="--mv-word-rotate-color:var(--mv-fg)"></mv-word-rotate> by default.</p>
</div>
<p style="margin:0;font-size:.85rem;color:var(--mv-fg-muted)">Hover a word to hold it. Screen readers hear each sentence once, with every option.</p>
</div>API
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
words | string | Words separated by commas (or |). Otherwise: one child per word. | |
effect | slide | flip | blur | fade | slide | Transition between two words; letters enter one after another. |
interval | number (ms) | 2600 | How long each word is shown. |
duration | number (ms) | 560 (680 for flip) | Duration of the transition and of the width glide. |
stagger | number (ms) | 18-30 (0 for fade) | Delay between letters. |
easing | CSS easing | var(--mv-ease-out) | Letter easing curve (tokens accepted). |
direction | up | down | up | Slide / flip direction. |
colors | list of CSS colors | One color per word, cycled. | |
conjunction | or | and | none | or | How the screen reader sentence joins the words: “designers, developers, or teams”. Uses the page language (lang). |
label | string | Replaces the screen reader sentence entirely. | |
paused | boolean | Pauses the rotation. It also holds by itself on hover, on focus of a wrapping link or button, off-screen and in hidden tabs. | |
data-variant | pill | Tinted pill whose width animates. | |
data-held | boolean | Set by the component while hover or focus holds the word (for styling). |
Properties
| Name | Type | Description |
|---|---|---|
index | number | Current word (settable, wraps around; assignable before the element is defined). |
Methods
| Name | Description |
|---|---|
next() | Next word. |
previous() | Previous word. |
Events
| Name | Description |
|---|---|
mv-change | New word shown (detail.index, detail.word). |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-word-rotate-color | inherit | Word color. |
--mv-word-rotate-duration | Default duration. | |
--mv-word-rotate-stagger | Default stagger. | |
--mv-word-rotate-easing | Letter easing curve. | |
--mv-word-rotate-width-easing | var(--mv-ease-emphasized) | Width glide easing curve. |
--mv-word-rotate-radius | 0.3em | Pill corner radius. |
Accessibility
The animated word is aria-hidden; a visually hidden sentence lists every option once (“designers, developers, or teams”, built with Intl.ListFormat in the page language), so screen readers never hear a change. There is no live region. The rotation holds while the pointer is on the word or while focus is inside a wrapping link or button, pauses off-screen and in hidden tabs, and under reduced motion shows one static word with no width animation. The pill keeps a visible outline in forced colors.