motion-react について
motion-reactは、MotionでUIアニメーションを作るReact開発者向けのスキルです。コンポーネント、ジェスチャー、レイアウトの遷移を扱い、動きを抑える配慮や性能、演出の節度を重視し、CSSやAutoAnimateとの使い分けも案内します。
主な機能
- 01表示・削除アニメーション
- 02バリアント制御とレイアウト遷移
- 03ジェスチャー状態と数値アニメーション
- 04動きを抑えるアクセシビリティ対応
- 05Motion、CSS、AutoAnimateの選択
活用シーン
- 01リスト項目の追加・削除をアニメーション化
- 02ページ遷移や共有要素の移動を実装
- 03カウンターやジェスチャー操作に反応を追加
- 04アニメーションのアクセシビリティと性能を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bm629/ agent-skills --skill motion-reactインストール後、Claude Code で/motion-reactを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/a11y-and-restraint.mdintegration-and-testing.mdlayout-and-shared-elements.mdsources.mdvalues-and-imperative.md詳細
motion-react — React 向け Motion
概要
Motion を使用して React で UI アニメーションを実装します。Motion は以前 framer-motion として公開されていたライブラリで、2024 年後半から独立し、npm パッケージ motion として公開されています("motion/react" からインポートします)。このスキルでは、宣言的な表示・終了アニメーション、バリアントのオーケストレーション、レイアウトと共有要素のトランジション、モーション値と数値カウンター、ジェスチャー状態など、DOM を使ったプロダクト UI アニメーションを扱います。また、3 つの必須事項を一貫して重視します。動きを抑える設定へのアクセシビリティ対応、コンポジターに適したパフォーマンス、そして節度(特にデータが密集したツールでは、目的に沿った短く一貫性のある動き)です。「そもそも Motion が必要か」という判断も扱います。多くの場合、単純な CSS や AutoAnimate の 1 行の呼び出しで十分です。
有効にするタイミング
- ✅ React SPA に表示・終了アニメーション、リストアニメーション、ページやビューのトランジション、共有要素の移動、アニメーション付きカウンター、ジェスチャーへのフィードバックを追加する場合。
- ✅
framer-motion(旧パッケージ)を参照するコードを移行または作成する場合。このスキルでは、現在のmotionのイディオムを説明します。 - ✅ 動きを抑える設定への対応を組み込む場合、または既存のアニメーションをアクセシビリティやパフォーマンスの観点から監査する場合。
- ✅ 特定のインタラクションに Motion、CSS/Tailwind のトランジション、AutoAnimate のどれを使うか選ぶ場合。
次の場合は有効にしないでください:
- アニメーション付きイラストや Lottie ファイルが対象の場合。これは UI の動きではなく画像表現です(専用のイラストスキルが扱います)。
- 動画のレンダリング(Remotion)、またはスクロール連動のストーリーテリングやパララックスを使ったマーケティングページが対象の場合。別ジャンルです。このスキルでは
whileInViewの基本だけを扱います。 - プロダクトのモーションデザイン言語(特定のアプリで採用する時間やイージング)を決める場合。これはデザインシステムの判断事項です。このスキルでは用語と制約を示します。
ワークフロー
ステップ 1:適切なツールを選ぶ — ほとんどのアニメーションに Motion は不要です
| 作業 | 使用するもの | 理由 |
|---|---|---|
| ホバー/フォーカス時の色、不透明度、小さなスケール変化 | シンプルな CSS/Tailwind の transition-* | JS 不要、バンドルサイズへの影響なし、GPU に適しています |
| Radix ベースのコンポーネント(アコーディオン、ポップオーバー、ダイアログ)の開閉スタイル | Radix の data-state 属性を使った CSS | プリミティブがすでに状態を公開しており、CSS でアニメーションできます |
| 内部ツールでのリスト項目の追加/削除/並べ替え | AutoAnimate — 親に useAutoAnimate() の ref を 1 つ設定 | 設定不要で子要素の追加/削除/移動をアニメーション化し、prefers-reduced-motion に自動対応します |
アンマウント時の終了アニメーション、オーケストレーションされたシーケンス、共有要素の移動、スプリング、数値カウンター、ドラッグ/ドラッグによる並べ替え(Reorder コンポーネント) | Motion | CSS では表現できない、JS によるライフサイクル制御が必要です |
| ブラウザー標準のビュー変形(同一ドキュメント内、またはドキュメント間/MPA) | View Transitions API | 選択肢として挙げています。React SPA でビュー/ルートを切り替える場合、AnimatePresence が同等の機能を提供します(テーマのクロスフェードのようなドキュメント全体の変形は VTA のみで可能です) |
よりシンプルな段階では本当に対応できない場合に限り、表を下へ進んでください。
ステップ 2:インストールしてアプリレベルの基本設定を行う
npm install motion
import { motion, MotionConfig } from "motion/react"
// App root — respect the user's OS reduced-motion setting everywhere:
<MotionConfig reducedMotion="user">
<App />
</MotionConfig>
- パッケージ名は
motionで、React のエントリーポイントは"motion/react"です。React 18 以降に対応しています(ドキュメントでは 18.2 と記載されており、peer dependency の範囲は^18.0.0 || ^19.0.0です)。framer-motionをインポートするコードは、リネーム前のパッケージです。同じ系譜のパッケージですが、新しいプロジェクトではmotionを使用し、現在のドキュメントや慣用的な書き方もこの名前で公開されています。 MotionConfig reducedMotionは"user"(OS の設定に従う)、"always"(常に削減する。デバッグ用)、"never"(デフォルト)を受け付けます。削減が有効な場合、Motion は変形とレイアウトのアニメーションを無効にし、透明度や色のアニメーションは維持します。通常、これが適切な縮退動作です。ルートで"user"をデフォルト設定として指定してください。設定の詳細についてはreferences/a11y-and-restraint.mdを参照してください。- バンドルサイズを削減するための設定は、次のラッパーひとつです。
<LazyMotion features={domAnimation} strict><m.div animate={{ opacity: 1 }} /></LazyMotion>. - React Server Component フレームワークでは、
motionコンポーネントはクライアントコンポーネントです。そのため、"use client"境界を追加するか、motion/react-clientからインポートしてください。通常の Vite SPA では、どちらも必要ありません。 - バンドルサイズに配慮が必要なアプリでは、
LazyMotionとmコンポーネント(import * as m from "motion/react-m")を使うと、初期読み込みは約 4.6 kB です(motionをすべて読み込む場合は約 34 kB)。機能(domAnimation)は同期的に読み込むか、最大限サイズを削減する場合はハイドレーション後に非同期で読み込めます。LazyMotionのstrictを有効にすると、完全版のmotionコンポーネントが誤って使われた場合にエラーになります。
ステップ 3:基本的なアニメーション
<motion.div
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2, ease: "easeOut" }}
/>
- マウント時に
initialからanimateへのアニメーションが実行されます。アンマウント時にexitが実行されるのは、AnimatePresenceの内側にある場合のみです(ステップ 5)。 transitionでアニメーションのモデルを選びます。type: "tween"は時間とイージングを指定するもので、UI のデフォルトです。type: "spring"は物理的な動きを再現し、ジェスチャーやドラッグに使用します。エントランスアニメーションでは控えめに使ってください。キーフレームには配列を渡します(animate={{ x: [0, 100, 0] }})。最初のキーフレームにnullを指定すると、「現在の値」を意味します。- ジェスチャーの状態には
whileHover、whileTap、whileFocus、whileDrag、whileInViewがあります。ジェスチャーが終了すると、値は元に戻ります。ホバーのみのスタイルには CSS を優先してください(ステップ 1)。ジェスチャーをほかのアニメーション値と連動させる必要がある場合は、これらを使います。 - プロダクト UI のアニメーション時間は、マイクロインタラクションなら 150~300 ms、大きなトランジションなら 400 ms 以下にします。これより長いと、洗練されているというより、遅く感じられます。
ステップ 4:バリアント — 親要素と子要素を連携させる
import { motion, stagger } from "motion/react"
const list = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { when: "beforeChildren", delayChildren: stagger(0.05) },
},
}
const item = { hidden: { opacity: 0, y: 4 }, visible: { opacity: 1, y: 0 } }
<motion.ul variants={list} initial="hidden" animate="visible">
{rows.map(r => <motion.li key={r.id} variants={item} />)}
</motion.ul>
- バリアント名は子要素に伝播します。親の状態が変化すると、
variantsを持つ子要素もアニメーションするため、props を何段階も渡す必要はありません。 - オーケストレーションは親要素の
transitionで設定します。when: "beforeChildren" | "afterChildren"と、delayChildren: stagger(interval)を指定します。これは現在の慣用的な書き方で、motion12.22.0 以降で利用できます(staggerChildren/staggerDirectionは 12.21.0 で非推奨になりました)。古いインストール環境(framer-motion、12.x の初期バージョン)では、staggerChildren: 0.05は引き続き使えますが、stagger()をdelayChildrenに渡す方法はサポートされていません(その場合、このオプションは数値のみを受け付けていました)。書き方を移行する前に、パッケージを更新してください。 - 動的なバリアント:バリアントは
customの関数にできます(例:インデックスごとに遅延を変える)。
Step 5: AnimatePresence — 退出アニメーション
import { AnimatePresence, motion } from "motion/react"
<AnimatePresence mode="popLayout">
{rows.map(r => (
<motion.div key={r.id} exit={{ opacity: 0, x: -8 }} layout />
))}
</AnimatePresence>
- 直接の子要素を監視する仕組みです。すべての子要素に**安定した一意の
key**が必要です (配列のインデックスを使うと、よくある失敗として退出アニメーションが壊れます)。 mode:"sync"(デフォルト。入場と退出を同時に実行)、"wait"(退出が完全に終わってから入場。一度に表示する子要素は1つ。ビューやルートの切り替えに適しています)、"popLayout"(退出する要素をレイアウトフローから外し、兄弟要素を再配置します。リストに適しています。親要素にはstatic以外のpositionが必要です)。- インプレースでのコンテンツ切り替え(スケルトン→コンテンツ、タブパネル)では、
"wait"を使う場合、2つの子要素の寸法を揃えないと隙間が一瞬表示されます。寸法が異なる場合は、"popLayout"か、グリッドスタック/絶対配置のオーバーレイを使ってインプレースでクロスフェードします。サイズ変更そのものもスナップではなくアニメーションさせる場合は、コンテナーにlayoutを指定します。 initial={false}を指定すると、初回のレンダリング時に存在する子要素のマウントアニメーションがスキップされます。onExitCompleteは、すべての退出アニメーションが完了したときに実行されます。- 退出中のコンポーネントには、プロパティの更新が渡されません。カルーセルやページネーション付きビューなど、方向に応じた退出アニメーションを実装する場合は、AnimatePresenceの
customプロパティで方向を渡し、子要素内でusePresenceData(またはバリアントのcustom)を使って取得します。 - AnimatePresenceは条件分岐を囲む必要があります。条件分岐の内側に配置してはいけません。
Step 6: コア機能の先へ — 用途に合ったリファレンスを参照する
- レイアウトアニメーション、
layoutIdによる共有要素、LayoutGroup、歪みの修正 →references/layout-and-shared-elements.md - モーション値、
useTransform/useSpring、命令型のanimate()/useAnimate、統計タイル用の数値カウントアップアニメーション →references/values-and-imperative.md - 軽減モーションに関する完全な仕様、WCAGとの対応、軽減する場合と維持する場合の表、モーション制限トークン →
references/a11y-and-restraint.md - Radix/shadcnとの統合(
forceMount)、Tailwindとの境界、ルーターのページ遷移、AutoAnimateの実例、テスト(MotionGlobalConfig.skipAnimations、Playwrightの軽減モーション) →references/integration-and-testing.md
ルール
必ず守るルール:
- 視差効果を減らす設定を尊重してください。 Motion を使用するすべてのアプリでは、ルートで
MotionConfig reducedMotion="user"(または同等の明示的な方法)を設定してください。OS の設定を無視する大きな移動、ズーム、視差効果、自動再生アニメーションはリリースしないでください(WCAG 2.3.3;5 秒を超える自動再生アニメーションには、WCAG 2.2.2 に従い一時停止コントロールが必要です)。 - レイアウトに影響するプロパティではなく、
transformとopacityをアニメーションさせてください。width/height/top/left/マージンを直接アニメーションさせないでください。代わりにlayoutプロパティ(transformを使ってアニメーションします)またはスケールを使用してください。レイアウトに影響しない低コストのプロパティ(色/背景、SVG のストローク値)は問題ありません。スケールを使った塗りつぶし(プログレスバー、メーター)には、明示的な変形の原点が必要です(左端を基準に塗りつぶす場合はoriginX: 0)。デフォルトは中央です。**認められている例外が 1 つあります:**展開/折りたたみの表示(アコーディオン、ディスクロージャー)では、overflow: hiddenを指定してheight: 0 ↔ "auto"をアニメーションさせます。スケールではテキストが歪み、layoutではクリップしながら表示できません。短時間で、ユーザー操作によって開始されるものにしてください。なお、視差効果を減らす設定によって、これは自動的に抑制されません(無効になるのはtransform/layoutのアニメーションのみです)。表示によって大量のコンテンツが押し下げられる場合は、useReducedMotion()を使って、設定が有効なときは即座に展開するようにしてください。 AnimatePresence内では安定したキーを使ってください。 キーに配列インデックスを使うと、終了アニメーションが気付かれないまま壊れます。"motion/react"からインポートしてください。 新しいプロジェクトにframer-motionを追加しないでください。両方のパッケージを混在させないでください。- Motion は目的を持たせてください。 アニメーションは状態の変化、空間的な関係、またはフィードバックを伝えるものです。プロダクト UI における装飾だけのアニメーションは、仕上げではなく不具合です。
推奨事項(必要に応じて変更可能):
- マイクロインタラクションは 150~300 ms、ルート/ページの切り替えは 200 ms 以下、その他のビュー単位の切り替えは 400 ms 以下(目標値ではなく上限)にしてください。
- UI の状態変化にはトゥイーンを、ジェスチャー駆動/物理的なインタラクションにはスプリングを使ってください。
- 期間やイージングは散在するリテラル値ではなく、デザイントークンとして一元管理してください。
- Motion を使う前に、必要十分な最もシンプルな方法(ステップ 1)を優先してください。
注意点
- **終了アニメーションが再生されない:**要素が
AnimatePresenceの直接の子ではない、キーが安定していない、または要素と一緒にAnimatePresence自体がアンマウントされている可能性があります。アニメーションではなく、ツリーを修正してください。 - **旧パッケージの書き方が混入する:**チュートリアルや LLM の生成結果には、
framer-motionのインポート、staggerChildren、motion(Component)時代のイディオムが頻繁に含まれます。現在の書き方は、motionパッケージ、delayChildren: stagger()、カスタムコンポーネントをラップするmotion.create(Component)です(コンポーネントは ref を公開する必要があります。React 18 ではforwardRef、React 19 では通常のrefプロパティを使います)。API が古そうに見える場合は、最新のドキュメントを確認してください。 - **
popLayoutでは位置指定が必要です:**終了する要素は絶対位置で配置されるため、親の位置指定がstaticだと、要素の位置がずれます。 - **レイアウトアニメーションで角丸やシャドウが歪む:**Motion がスケール補正できるよう、
borderRadius/boxShadowをstyleで指定する(またはアニメーションさせる)とともに、伸縮する子要素にも独自のlayoutプロパティを指定してください。 - **マウント時のスプリングが弾みすぎて遅く感じる:**剛性/減衰で設定する物理ベースのスプリングは、独自に収束時間を算出するため、指定した時間の期待に従いません。表示時には、時間ベースのスプリング(
type: "spring", duration, bounce)または 200 ms のトゥイーンを使用してください。 - **Motion の値を変更しても React は再レンダリングされません:**JSX で
{x.get()}をレンダリングすると値が古いままになります。Motion の値はmotion要素の子としてレンダリングするか、useMotionValueEventを使って購読してください。 - **アニメーションのせいでテストがハングしたり不安定になったりする:**テストのセットアップで
MotionGlobalConfig.skipAnimations = trueを設定し、最終状態を検証してください(統合リファレンスを参照)。 - **jsdom にはレイアウト機能がありません:**レイアウトアニメーションと
whileInViewには実際の計測値が必要です。状態ロジックはユニットテストで、表示は E2E テストで検証してください。
アンチパターン
- 「すべてをアニメーションさせれば、高級感が出ます。」 データ量の多いツールでは、一貫性のある短く目的に沿ったアニメーションを少数使うことで洗練された印象になります。動きが多すぎると理解が遅れます。
- 「モーション軽減への対応は後回しにして、後で追加すればよい。」 最初に対応すればルートレベルの1行で済みますが、後から対応すると監査が必要になります。「後で」はありません。
- 「高さをアニメーションさせればよい。」 レイアウトプロパティはメインスレッド上でカクつきます。
layoutprop を使うか、別のデザインにしてください。 - 「AutoAnimate では力不足なので、リストを Motion で書き直そう。」 リストに必要なのが追加・削除・移動だけなら、30行の variants より ref ひとつで済みます。
- 「2023年のブログ記事にある framer-motion のスニペットをコピーしよう。」 現行のドキュメントで確認してください。パッケージ、インポート、stagger の慣用的な書き方は変わっています。
成果物
React のコードベースで動作するアニメーションコードです。motion/react のプリミティブを使うコンポーネント(または Step-1 の表に沿った、意図的によりシンプルな階層)、アプリレベルでのモーション軽減への対応、アニメーションコンポーネントのテストを決定論的にする設定を含みます。利用者はコードベースのレビュアーとテストスイートです。アクセシビリティ、パフォーマンス、抑制が最初から満たされたアニメーションを提供します。
関連項目
- UI/UX デザインガイドラインのスキル(アニメーションの時間や意味に関するルールを定めるものなど)は、何をいつアニメーションさせるかを決める METHOD の情報源です。このスキルは実装を担います。
- コンポーネントのスタイリングスキル(Radix/Tailwind)は、Step-1 の表にある
data-stateの CSS 階層を担います。 - ルータースキル(TanStack Router など)はルート構造を担います。このスキルはルートビューをラップしてトランジションを適用するだけです。
- イラストスキルは Lottie やアニメーション画像を担います。隣接する領域ですが、このスキルの対象ではありません。
- コンポーネントテストスキルは、このスキルのテストガイダンスが利用する RTL/vitest ハーネスを担います。
段階的な読み込み
references/layout-and-shared-elements.md— レイアウト変更、共有要素(layoutId)、リストの並べ替えをアニメーションさせる場合に読み込みます。references/values-and-imperative.md— モーション値、トランスフォーム/スプリング、命令的なシーケンス、アニメーションする数値カウンターを扱う場合に読み込みます。references/a11y-and-restraint.md— モーション軽減への対応、アクセシビリティの監査、モーショントークン/抑制ルールの定義を行う場合に読み込みます。references/integration-and-testing.md— Motion を Radix/shadcn、Tailwind、またはルーターと組み合わせる場合、AutoAnimate を使う場合、またはテストにアニメーションコンポーネントが含まれる場合に読み込みます。references/sources.md— 調査の出典情報です。主張を監査する場合にのみ読み込みます。
本文の上限
descriptionは1,024文字以下です(agentskills.io の上限)。- 本文は約500行/5,000トークンを目安とします。超過分は
references/に置きます。