Retour au catalogue

Process Path Draw

SVG path qui se dessine entre les etapes au scroll (stroke-dashoffset anime via useScroll). Cercles numerotes relies par un trait.

processcomplex Both Responsive a11y
elegantminimaluniversalsaasagencystacked
Theme

Créer une animation SVG path draw au scroll en React

Pour animer un SVG qui se dessine au scroll en React, utilise useScroll de Framer Motion pour obtenir un scrollYProgress, transforme-le en valeur pathLength avec useTransform, et applique-le à un élément motion.path. Le tracé apparaît progressivement à mesure que la section défile.

  • Stack : React + Framer Motion 11 + CSS custom properties, ~46 lignes, zéro dépendance supplémentaire.
  • API principales : useScroll, useTransform, motion.path, la motion value pathLength.
  • Le chemin SVG est généré dynamiquement depuis le tableau de steps, donc ajouter une étape étend la ligne automatiquement.
  • Accessible : titres et descriptions des étapes sont du texte DOM standard ; le SVG est décoratif (aucun aria role requis).
  • Responsive par défaut. Sur les petits écrans, le max-width et le padding-left du conteneur adaptent correctement la mise en page.

Process Path Draw est une timeline verticale où un trait reliant des cercles numérotés se dessine au fil du scroll. L'animation remplace une liste statique par un mouvement qui traduit visuellement l'idée de progression : chaque étape se révèle au moment où l'utilisateur y arrive. Le composant s'intègre naturellement dans des flows d'onboarding, des études de cas d'agence ou des sections produit.

Anatomie

Une section pleine largeur contient un header centré (h2 + sous-titre) et une colonne contrainte (max 680px). Dans cette colonne, un SVG est positionné en absolu sur le bord gauche, large de 2rem, couvrant toute la hauteur. Il superpose deux chemins identiques : un path gris statique comme rail, et un motion.path de couleur accent dont le pathLength s'anime de 0 à 1. Les cartes d'étapes se placent à droite du SVG, chacune avec un cercle numéroté positionné en absolu en alignement avec le tracé.

Comment ça marche

La clé repose sur la motion value pathLength de Framer Motion. Une ref sur le conteneur principal est passée à useScroll avec l'offset ['start 0.75', 'end 0.6'], ce qui fait passer scrollYProgress de 0 à 1 quand le conteneur traverse le viewport. useTransform mappe directement ce 0-1 vers un pathLength 0-1. En l'appliquant à un motion.path, Framer Motion anime la propriété CSS stroke-dashoffset, le mécanisme natif du navigateur pour tracer les SVG progressivement. Chaque carte d'étape entre en fondu via whileInView, avec un décalage par index.

Comment le coder en React

  1. Calcule la géométrie du chemin depuis tes étapes

    Construis l'attribut d du SVG en mappant ton tableau de steps. Chaque étape est espacée de 180 unités verticalement dans un viewBox de 100 unités de large. Un cx=50 fixe maintient le trait centré sur la colonne SVG de 2rem.

    const cx = 50;
    const pathD = steps
      .map((_, i) => `${i === 0 ? "M" : "L"} ${cx} ${i * 180 + 20}`)
      .join(" ");
  2. Relie le scroll au pathLength

    Attache une ref au div conteneur et passe-la à useScroll. Le tableau offset contrôle à quels moments du scroll l'animation commence et se termine. useTransform convertit le scrollYProgress brut 0-1 en motion value pathLength.

    const containerRef = useRef<HTMLDivElement>(null);
    const { scrollYProgress } = useScroll({
      target: containerRef,
      offset: ["start 0.75", "end 0.6"],
    });
    const pathLength = useTransform(scrollYProgress, [0, 1], [0, 1]);
  3. Affiche le SVG à deux couches

    Positionne un SVG en absolu à côté de la colonne des étapes. Trace d'abord le path gris statique en guise de rail visuel, puis le motion.path avec le style pathLength. Les deux partagent le même d. Mets preserveAspectRatio='none' pour que le trait s'étire à la hauteur réelle de la colonne quel que soit le nombre d'étapes.

    <motion.path
      d={pathD}
      stroke="var(--color-accent)"
      strokeWidth="3"
      strokeLinecap="round"
      style={{ pathLength }}
    />
  4. Aligne les puces d'étapes sur le tracé

    Chaque carte d'étape a position:relative. À l'intérieur, un cercle positionné en absolu à left:-4.5rem correspond à la largeur de la colonne SVG plus l'espace. Un double box-shadow (couleur de fond puis couleur accent) crée l'effet de nœud sur la ligne sans élément DOM supplémentaire.

Quand l'utiliser

Utilise Process Path Draw quand tu as 3 à 5 étapes séquentielles et que tu veux donner du poids visuel à chacune au scroll. Il convient aux explications d'onboarding, aux sections méthodologie des sites d'agence et aux flows produit. Évite-le quand les étapes sont réellement parallèles ou quand la page est trop courte pour que le scroll déclenche l'animation de façon significative. Sur des pages avec beaucoup d'animations au scroll, teste le budget global pour éviter les ralentissements.

Utilisé par

  • Stripe, Utilise des lignes de connexion verticales dans ses sections explicatives pour guider le regard à travers un flux de paiement multi-étapes.
  • Linear, Des connecteurs animés entre étapes de workflow apparaissent sur ses pages features et changelog, renforçant l'idée de progression séquencée.
  • Lottiefiles, Les animations de type path-draw sont un format mis en avant sur la plateforme, illustrant la technique dans les pages marketing.

FAQ

Comment contrôler la vitesse de l'animation de dessin ?

Ajuste le tableau offset dans useScroll. Une plage plus serrée comme ['start 0.6', 'end 0.8'] accélère le dessin sur une courte distance de scroll. L'élargir à ['start 0.9', 'end 0.2'] ralentit l'animation sur une plus grande distance.

Peut-on utiliser un chemin courbe plutôt que des lignes droites ?

Oui. Remplace les commandes M/L dans pathD par des courbes de Bézier avec les commandes C ou Q. L'animation pathLength fonctionne sur n'importe quel chemin SVG valide, donc la technique est agnostique à la géométrie.

Pourquoi le SVG utilise preserveAspectRatio='none' ?

La hauteur du viewBox est calculée depuis le nombre d'étapes (steps.length * 180), mais la hauteur rendue du SVG est 100% du conteneur. Sans preserveAspectRatio='none', le navigateur appliquerait un letterbox ou couperait le tracé. La valeur 'none' étire la géométrie pour remplir exactement l'élément.

L'animation se rejoue-t-elle quand l'utilisateur remonte ?

Le pathLength est une motion value liée en direct à la position de scroll, donc il se renverse naturellement quand on remonte. Les cartes d'étapes utilisent whileInView avec once:true, elles restent donc visibles après leur première apparition.

"use client";

import { useRef } from "react";
import { motion, useScroll, useTransform } from "framer-motion";

interface Step { number: number; title: string; description: string }
interface ProcessPathDrawProps { title?: string; subtitle?: string; steps?: Step[] }

const E = [0.16, 1, 0.3, 1] as const;
const HEAD: React.CSSProperties = { fontFamily: "var(--font-sans)", fontSize: "clamp(2rem, 4vw, 3rem)", fontWeight: 700, lineHeight: 1.1, letterSpacing: "-0.02em", color: "var(--color-foreground)", marginBottom: "1rem" };

export default function ProcessPathDraw({ title = "Notre demarche", subtitle = "Un chemin clair vers votre succes.", steps = [] }: ProcessPathDrawProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const { scrollYProgress } = useScroll({ target: containerRef, offset: ["start 0.75", "end 0.6"] });
  const pathLength = useTransform(scrollYProgress, [0, 1], [0, 1]);
  const cx = 50;
  const pathD = steps.map((_, i) => `${i === 0 ? "M" : "L"} ${cx} ${i * 180 + 20}`).join(" ");

  return (
    <section style={{ paddingTop: "var(--section-padding-y-lg)", paddingBottom: "var(--section-padding-y-lg)", background: "var(--color-background)" }}>
      <div style={{ maxWidth: "var(--container-max-width)", margin: "0 auto", padding: "0 var(--container-padding-x)" }}>
        <div style={{ textAlign: "center", marginBottom: "4rem" }}>

Code complet réservé à Pro

Code source intégral, export multi-framework et playground.

Passer en Pro, 9,99€/mois

Avis

SVG path animé au scroll en React, timeline de process