Letter Swap <mv-letter-swap>

ナビゲーションリンクとボタンのための文字ごとのロール:ホバーやキーボードフォーカスで各文字が転がって消え、その分身が現れます。カスケード表示や、小さな 3D キューブとして回転させることもできます。

仕組み

ナビゲーションリンクとボタンのための文字ごとのロール:ホバーやキーボードフォーカスで各文字が転がって消え、その分身が現れます。カスケード表示や、小さな 3D キューブとして回転させることもできます。実際の文字は DOM の中に、それぞれ固定されたボックスに収まったまま残るので、ラベルがリフローすることはなく、単語の間で折り返し、選択可能なままで、実行時に変更することもできます。

カテゴリーアニメーションテキスト
タイプWeb Component(<mv-letter-swap>)
ステータス安定版
Keywordsletter, swap, roll, flip, 3d, hover, nav, button, stagger, accessible

When to use

  • Nav links or button labels should roll their letters on hover and keyboard focus
  • A 3D cube flip of each letter suits a playful or technical brand
  • A short label should roll once when it enters the viewport, on page load or on demand
  • The revealed letters should take an accent color while a control is hovered

Avoid when

  • A different label must roll in on hover, or a highlighter should glide between phrases → use Rolling Text instead
  • Long sentences or paragraphs; the per-letter roll is meant for short labels
  • The label is underlined; per-letter boxes do not carry the parent text decoration

インストール

node scripts/add.mjs letter-swap --out ./src/marvelous

Marvelous UI の MCP サーバーを使う AI エージェント:install_components({ slugs: ["letter-swap"], target_dir: "<absolute path>/src/marvelous", framework: "react" })。

コピーされるファイル(依存関係を含む):tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, core/observe.js, components/letter-swap/letter-swap.js, components/letter-swap/letter-swap.css。

使い方

基本となるマークアップです。ここから属性、data-*、CSS 変数でカスタマイズしてください:

<div style="display:grid;gap:2.25rem;justify-items:center;text-align:center">
  <nav aria-label="Demo" style="display:flex;gap:.25rem;padding:.35rem;border:1px solid var(--mv-border);border-radius:999px;background:var(--mv-surface);box-shadow:var(--mv-shadow-sm)">
    <a href="#" style="padding:.45rem .9rem;border-radius:999px;color:var(--mv-fg);text-decoration:none;font:500 .9rem var(--mv-font-sans)"><mv-letter-swap>Work</mv-letter-swap></a>
    <a href="#" style="padding:.45rem .9rem;border-radius:999px;color:var(--mv-fg);text-decoration:none;font:500 .9rem var(--mv-font-sans)"><mv-letter-swap stagger-from="center">Studio</mv-letter-swap></a>
    <a href="#" style="padding:.45rem .9rem;border-radius:999px;color:var(--mv-fg);text-decoration:none;font:500 .9rem var(--mv-font-sans)"><mv-letter-swap stagger-from="random">Journal</mv-letter-swap></a>
    <a href="#" style="padding:.45rem .9rem;border-radius:999px;background:var(--mv-fg);color:var(--mv-bg);text-decoration:none;font:500 .9rem var(--mv-font-sans)"><mv-letter-swap direction="down">Contact</mv-letter-swap></a>
  </nav>

  <p style="margin:0;font:800 clamp(2.2rem,6vw,3.8rem)/1 var(--mv-font-sans);letter-spacing:-.045em;text-transform:uppercase">
    <mv-letter-swap variant="flip" trigger="view" loop stagger="45" duration="700">Creative</mv-letter-swap>
    <span style="color:var(--mv-fg-muted)">by nature</span>
  </p>

  <div style="display:flex;gap:.75rem;flex-wrap:wrap;justify-content:center">
    <button class="mv-button" data-size="lg"><mv-letter-swap variant="flip" stagger="30">Start for free</mv-letter-swap></button>
    <button class="mv-button" data-size="lg" data-variant="outline"><mv-letter-swap stagger="15" duration="420" easing="out" style="--mv-letter-swap-twin:var(--mv-accent)">Watch the demo</mv-letter-swap></button>
  </div>
</div>

API

Attributes

NameタイプDefaultDescription
textstringLabel to roll. Defaults to the element text; changing it rebuilds the letters.
variantslide | flipslideslide: the letter slides; flip: a rotating 3D cube.
triggerhover | view | load | manualhoverhover follows the parent link or button (mouse or pen hover, keyboard focus); view and load roll once; manual waits for replay().
directionup | downupRoll direction: up (the twin rises from below) or down.
durationnumber500Duration per letter (ms).
staggernumber22Delay between letters (ms).
stagger-fromstart | center | end | randomstartWhere the cascade starts.
delaynumber0Initial delay (ms).
easingCSS easingvar(--mv-ease-in-out)Easing curve: any CSS easing, or a token name (out, in, in-out, emphasized, spring, bounce, snappy).
loopbooleanWith view, load or manual: keeps rolling while visible, pausing 1.6 s between rolls.

Properties

NameタイプDescription
labelstringRead only. The label as announced to screen readers.

Methods

NameDescription
replay()Rolls every letter once and settles back invisibly. Returns a Promise resolved when done (at once under reduced motion).

CSS variables

NameDefaultDescription
--mv-letter-swap-leading1.2Unitless line height of each letter box (the clipping window). The extra leading is cancelled, so the line keeps its height.
--mv-letter-swap-easingvar(--mv-ease-in-out)Default easing curve.
--mv-letter-swap-twincurrentColorColor of the revealed twin while hovered or focused (a replay always lands on identical letters).
--mv-letter-swap-perspective20emPerspective depth (flip variant).

Accessibility

Screen readers get the label once, as plain text; the rolling letters are aria-hidden, so there is no per-letter reading. The real letters stay in the DOM (selectable, copied once) and the twin is drawn by CSS. Hover follows the parent control and its keyboard :focus-visible; touch does not trigger it. Each letter keeps a fixed box, so nothing reflows. Reduced motion, print and forced colors show static text.

このページは AI で翻訳されています。翻訳の問題を報告