Tips & Tricks (Mis à jour: 02/06/2026)

Claude Code et Framer Motion : guide pratique Motion for React

Utilisez Claude Code avec Framer Motion/Motion for React : prompts, exemples TSX, pièges, accessibilité et vérification.

Claude Code et Framer Motion : guide pratique Motion for React

Beaucoup d’équipes cherchent encore Framer Motion, mais la documentation officielle actuelle présente la bibliothèque comme Motion for React. Pour un nouveau développement, installez motion et importez les APIs React depuis motion/react. Si une application existante est déjà standardisée sur framer-motion, ne mélangez pas les deux styles sans décision explicite. Pour une nouvelle implémentation, prenez la documentation Motion for React comme référence.

Claude Code peut accélérer l’ajout d’animations, mais il ne remplace pas le jugement produit. Un prompt vague comme “rends cette interface plus fluide” produit souvent des mouvements trop visibles, oublie Reduced Motion ou casse les animations de sortie parce que le parent est démonté trop tôt. Masa a testé ce flux sur un tableau de bord interne : la première version était séduisante en démo, mais les cartes bougeaient trop, les notifications disparaissaient sans exit et l’en-tête au scroll était lourd sur une machine modeste.

La bonne approche consiste à utiliser Claude Code comme un collaborateur avec contraintes. On définit l’intention, le périmètre, l’accessibilité et les étapes de vérification avant de lui demander de modifier le code. Les exemples TSX ci-dessous fonctionnent dans un projet React après npm install motion. Avec Next.js ou Astro, isolez-les dans des composants client.

Commencer par les contraintes

Une animation doit expliquer un changement d’état. Elle ne doit pas devenir un coût visuel imposé à chaque ouverture d’écran. Avant de demander le changement, clarifiez les points suivants.

DécisionÀ transmettre à Claude CodeÀ vérifier
ObjectifQuel changement d’état doit être aidéL’animation améliore la compréhension
PérimètreFichiers autorisés et interditsAucun refactoring hors sujet
APImotion/react et Reduced MotionLes imports suivent la documentation
ValidationTests manuels, clavier, machine lenteLa vérification ressemble à un vrai usage

Le schéma de travail peut rester simple :

Intention et contraintes
  -> prompt Claude Code
  -> implémentation Motion for React
  -> vérification manuelle et accessibilité
  -> prompt de correction ciblé

Un premier prompt utile ressemble à ceci :

Ajoute une animation Motion for React à ce composant React existant.
Contraintes :
- Importer les nouvelles APIs depuis `motion/react`
- Ne pas modifier fetch, submit de formulaire ni routing
- Respecter Reduced Motion
- Préférer opacity et transform
- Éviter le layout shift
- Fournir une checklist de tests manuels

Cette précision évite que Claude Code récupère un exemple ancien avec framer-motion. L’import source doit être une règle du dépôt, pas une préférence implicite.

Cas 1 : listes de cartes animées

Les dashboards, grilles d’articles et cartes de fonctionnalités profitent d’un stagger discret. Le but n’est pas de faire danser les cartes, mais de créer un ordre de lecture. Dans le test de Masa, un décalage de 0,06 à 0,09 seconde était utile pour six cartes ; au-delà, l’interface semblait attendre avant de devenir utilisable.

import { motion, useReducedMotion } from "motion/react";

type Feature = {
  id: string;
  title: string;
  body: string;
  metric: string;
};

const demoFeatures: Feature[] = [
  {
    id: "review",
    title: "Revue en attente",
    body: "Changements générés par Claude Code à relire par une personne.",
    metric: "8 éléments",
  },
  {
    id: "motion",
    title: "Nettoyage du mouvement",
    body: "Des transitions courtes expliquent les changements sans ralentir.",
    metric: "14%",
  },
  {
    id: "a11y",
    title: "Reduced Motion",
    body: "Les grands déplacements deviennent un fondu plus calme.",
    metric: "Prêt",
  },
];

export function AnimatedFeatureCards({
  items = demoFeatures,
}: {
  items?: Feature[];
}) {
  const shouldReduceMotion = useReducedMotion();

  const container = {
    hidden: { opacity: 0 },
    visible: {
      opacity: 1,
      transition: {
        staggerChildren: shouldReduceMotion ? 0 : 0.08,
      },
    },
  };

  const card = {
    hidden: {
      opacity: 0,
      y: shouldReduceMotion ? 0 : 16,
    },
    visible: {
      opacity: 1,
      y: 0,
      transition: {
        duration: 0.32,
        ease: "easeOut",
      },
    },
  };

  return (
    <motion.section
      aria-label="Cartes de fonctionnalités"
      variants={container}
      initial="hidden"
      animate="visible"
      style={{
        display: "grid",
        gap: 16,
        gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
      }}
    >
      {items.map((item) => (
        <motion.article
          key={item.id}
          variants={card}
          whileHover={shouldReduceMotion ? undefined : { y: -4 }}
          style={{
            border: "1px solid #d9e2ec",
            borderRadius: 12,
            padding: 20,
            background: "#ffffff",
            boxShadow: "0 8px 24px rgba(15, 23, 42, 0.08)",
          }}
        >
          <p style={{ margin: 0, color: "#2563eb", fontWeight: 700 }}>
            {item.metric}
          </p>
          <h3 style={{ margin: "8px 0", fontSize: 18 }}>{item.title}</h3>
          <p style={{ margin: 0, lineHeight: 1.7, color: "#475569" }}>
            {item.body}
          </p>
        </motion.article>
      ))}
    </motion.section>
  );
}

La revue doit vérifier les clés stables, le mouvement basé sur transform et la désactivation des grands déplacements avec Reduced Motion. Un bon prompt de suivi serait : “Conserve le stagger, mais rends la liste immédiatement utilisable avec 12 cartes”.

Cas 2 : notifications avec sortie

AnimatePresence permet d’animer un élément quand il quitte l’arbre React. La documentation AnimatePresence rappelle que les enfants directs doivent avoir une key stable. L’erreur fréquente est de rendre conditionnel tout le conteneur de notifications, ce qui supprime le parent avant l’exécution de exit.

import { useState } from "react";
import { AnimatePresence, motion } from "motion/react";

type Toast = {
  id: number;
  message: string;
};

let nextToastId = 1;

export function AnimatedNotifications() {
  const [toasts, setToasts] = useState<Toast[]>([
    { id: 0, message: "Enregistré avec succès" },
  ]);

  function addToast() {
    const id = nextToastId++;
    setToasts((current) => [
      ...current,
      { id, message: `Tâche en arrière-plan ${id} terminée` },
    ]);
  }

  function dismissToast(id: number) {
    setToasts((current) => current.filter((toast) => toast.id !== id));
  }

  return (
    <div>
      <button type="button" onClick={addToast}>
        Ajouter une notification
      </button>

      <div
        aria-live="polite"
        style={{
          position: "fixed",
          right: 24,
          top: 24,
          display: "grid",
          gap: 12,
          width: "min(360px, calc(100vw - 48px))",
        }}
      >
        <AnimatePresence initial={false} mode="popLayout">
          {toasts.map((toast) => (
            <motion.div
              layout
              key={toast.id}
              initial={{ opacity: 0, x: 40, scale: 0.96 }}
              animate={{ opacity: 1, x: 0, scale: 1 }}
              exit={{ opacity: 0, x: 40, scale: 0.96 }}
              transition={{ duration: 0.2, ease: "easeOut" }}
              style={{
                borderRadius: 10,
                border: "1px solid #cbd5e1",
                background: "#ffffff",
                padding: 16,
                boxShadow: "0 12px 30px rgba(15, 23, 42, 0.16)",
              }}
            >
              <p style={{ margin: "0 0 12px", color: "#0f172a" }}>
                {toast.message}
              </p>
              <button type="button" onClick={() => dismissToast(toast.id)}>
                Fermer
              </button>
            </motion.div>
          ))}
        </AnimatePresence>
      </div>
    </div>
  );
}

Demandez ensuite à Claude Code de vérifier que le conteneur reste monté à zéro notification, que le bouton fonctionne au clavier et que aria-live n’annonce pas trop de contenu. Une notification est vue souvent ; elle doit être calme.

Cas 3 : progression de lecture

Sur une documentation longue, un onboarding ou une landing page, un indicateur de progression aide l’utilisateur à se situer. useScroll renvoie la progression de la page ou d’un élément sous forme de MotionValue. Avec useSpring, la barre semble plus stable. Évitez de transformer chaque section en parallax ; avec Reduced Motion, retirez les grands déplacements.

import { useRef } from "react";
import {
  motion,
  useReducedMotion,
  useScroll,
  useSpring,
  useTransform,
} from "motion/react";

const sections = [
  {
    title: "Figer le besoin",
    body: "Avant toute édition, Claude Code doit connaître l'objectif, les fichiers et les limites.",
  },
  {
    title: "Bouger moins",
    body: "Commencez par opacity et transform pour soutenir la compréhension.",
  },
  {
    title: "Vérifier le vrai parcours",
    body: "Testez machine lente, clavier et Reduced Motion avant publication.",
  },
];

export function ScrollReadingProgress() {
  const articleRef = useRef<HTMLElement | null>(null);
  const shouldReduceMotion = useReducedMotion();
  const { scrollYProgress } = useScroll({
    target: articleRef,
    offset: ["start start", "end end"],
  });

  const scaleX = useSpring(scrollYProgress, {
    stiffness: 120,
    damping: 28,
    mass: 0.2,
  });
  const y = useTransform(scrollYProgress, [0, 1], [0, -48]);

  return (
    <article ref={articleRef} style={{ position: "relative", padding: 24 }}>
      <motion.div
        aria-hidden="true"
        style={{
          position: "sticky",
          top: 0,
          zIndex: 10,
          height: 4,
          scaleX: shouldReduceMotion ? 1 : scaleX,
          transformOrigin: "0% 50%",
          background: "#2563eb",
        }}
      />

      <motion.header
        style={{
          y: shouldReduceMotion ? 0 : y,
          padding: "56px 0 32px",
        }}
      >
        <p style={{ color: "#2563eb", fontWeight: 700 }}>
          Claude Code x Motion
        </p>
        <h2 style={{ fontSize: 36, margin: 0 }}>
          Une page qui révèle le contexte pendant la lecture
        </h2>
      </motion.header>

      <div style={{ display: "grid", gap: 24 }}>
        {sections.map((section) => (
          <section
            key={section.title}
            style={{
              border: "1px solid #dbe4ee",
              borderRadius: 12,
              padding: 24,
              background: "#ffffff",
            }}
          >
            <h3>{section.title}</h3>
            <p style={{ lineHeight: 1.8 }}>{section.body}</p>
          </section>
        ))}
      </div>
    </article>
  );
}

Utilisez ce motif pour orienter, pas pour remplir l’espace. Une barre de progression utile vaut mieux que plusieurs effets au scroll qui ralentissent la lecture.

Faire relire le diff par Claude Code

Après l’implémentation, demandez une revue critique basée sur les modes d’échec.

Relis le diff actuel comme une implémentation Motion for React.
Sois strict sur :
- Pas de mélange entre `motion/react` et les anciens imports `framer-motion`
- Les enfants directs de `AnimatePresence` ont une key stable
- Reduced Motion désactive grands déplacements, parallax et effets type autoplay
- Le code n'anime pas souvent width, height, top ou left
- Les tests manuels correspondent à de vraies actions utilisateur

Ce prompt transforme Claude Code en premier reviewer. Comme il peut lire les fichiers voisins, il peut aussi repérer des conflits CSS, un état modifié par erreur ou des tests manquants.

Pièges et checklist

Le premier piège est l’import ancien. Dans un projet legacy, conserver framer-motion peut être cohérent, mais le code neuf devrait suivre motion et motion/react sauf décision contraire. Le deuxième est de chercher un problème d’easing alors que exit ne s’exécute pas. La cause est souvent le parent démonté trop tôt, une key basée sur l’index ou un élément qui ne sort pas via AnimatePresence.

Le troisième piège est de croire que layout corrige tout. Il aide pour le réordonnancement et les changements de taille, mais les images sans dimensions, les polices tardives et les changements brusques de Grid provoquent encore des sauts. Le quatrième est de repousser l’accessibilité. Le guide officiel Accessibilité explique Reduced Motion ; si votre design contient de grands déplacements, du parallax ou de l’autoplay, créez l’alternative dès la première version.

Avant publication, confirmez que les imports suivent la documentation, que chaque animation a un but, que Reduced Motion retire les grands mouvements, que les enfants de AnimatePresence ont une key, que le clavier et le focus restent utilisables et que les effets de scroll ne nuisent pas à la lecture.

Pour les fondations UI, consultez Radix UI avec Claude Code, shadcn/ui avec Claude Code et le guide d’animation Claude Code. Pour l’agent lui-même, gardez ouverte la documentation Claude Code d’Anthropic.

Conclusion

Associer Claude Code et Framer Motion ne sert pas seulement à produire plus vite une animation agréable. L’intérêt est de placer implémentation, accessibilité et revue dans le même flux avant la publication.

Le résultat concret de Masa est net : ajouter motion/react, Reduced Motion et la vérification manuelle dans le premier prompt a réduit davantage de retours que les ajustements faits après coup. Pour réutiliser le modèle, gardez la fiche gratuite. Pour auditer plusieurs écrans avec une équipe, la page formation et conseil est l’étape la plus pragmatique.

#Claude Code #Framer Motion #Motion for React #React #animation #UI/UX
Gratuit

PDF gratuit: cheatsheet Claude Code

Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.

Nous protégeons vos données et n'envoyons pas de spam.

Masa

À propos de l'auteur

Masa

Ingénieur spécialisé dans les workflows pratiques avec Claude Code.