Retour au catalogue

Breadcrumb Path Visual

Fil d'Ariane visuel avec icones colorees, badges de progression et ligne de connexion entre les etapes.

breadcrumbmedium Both Responsive a11y
playfulelegantsaaseducationuniversalstacked
Theme

Creer un breadcrumb React anime avec icones et progression d'etapes

Un breadcrumb visuel avec statut de progression en React affiche chaque etape comme un badge icone avec un etat completed/current/upcoming, les relie par des lignes animees et echelonne leur entree via Framer Motion. Trois variantes de statut pilotent toutes les couleurs via une seule fonction getStatusStyles qui lit les CSS custom properties.

  • Stack : React 18 + Framer Motion 11 + lucide-react + Tailwind v4, ~207 lignes, zero dependance runtime supplementaire.
  • Animation : entree echelonnee scale + opacity (0.1s de delai par item) avec une ease spring [0.16, 1, 0.3, 1].
  • L'etape en cours pulse avec une animation scale infinie sur la bordure de l'anneau pour attirer l'attention.
  • Accessible : rendu comme <nav aria-label> + liste <ol>, HTML semantique pour les lecteurs d'ecran.
  • Responsive sur petits ecrans, mais les libelles longs peuvent deborder sous 480px, a rogner ou passer en multilignes.

Breadcrumb Path Visual est un composant de navigation React qui va plus loin qu'un simple fil de liens. Chaque etape porte une icone, un etat de progression et une courte ligne de connexion animee, transformant un indicateur de position statique en une carte lisible de l'avancement dans un parcours multi-etapes. Le stagger d'entree et l'anneau pulsant sur l'etape courante lui conferent un rendu produit soigne.

Anatomie

Le composant est un <nav> semantique qui enveloppe une liste <ol>. Chaque <li> contient une ancre avec deux elements visuels : un badge icone circulaire de 32px et un libelle texte. Les etapes completees affichent aussi un badge CheckCircle de 12px pres du libelle. Entre les items, une courte ligne horizontale animee (20px, entree en scaleX) et une fleche ChevronRight servent de separateur visuel. Toutes les couleurs viennent de CSS custom properties, so le composant s'adapte a n'importe quel preset de theme sans toucher au TSX.

Comment ça marche

Chaque item de liste se monte avec un couple initial/animate Framer Motion (opacity 0 -> 1, scale 0.9 -> 1) et un delai de i * 0.1s pour que les items cascadent de gauche a droite. La ligne de connexion entre les items utilise une motion.div separee avec initial scaleX:0, animate scaleX:1 et un delai legerement plus tardif (i * 0.1 + 0.2s) pour que la ligne se dessine apres le badge de l'etape. L'anneau pulsant sur l'etape courante est une motion.div positionnee en absolu qui boucle scale [1, 1.4, 1] et opacity [0.4, 0, 0.4] sur une repetition de 2 secondes, creant une pulsation sonar sans timer JavaScript. La fonction getStatusStyles est la source unique de verite pour les trois etats, retournant des litteraux d'objet qui mappent sur des CSS custom properties plutot que des couleurs hardcodees.

Comment le coder en React

  1. Definir la forme des donnees et la map d'icones

    Cree une interface PathStep avec label, href, icon (cle string) et un type union status. Construis un objet iconMap qui mappe des cles string vers des composants d'icones Lucide. Ainsi les donnees mock restent du JSON simple et le composant resout les icones au runtime.

    interface PathStep {
      label: string;
      href?: string;
      icon?: string;
      status: "completed" | "current" | "upcoming";
    }
    
    const iconMap: Record<string, React.ElementType> = {
      Home,
      Package,
      Settings,
      CheckCircle,
    };
  2. Associer chaque statut aux tokens CSS custom properties

    Ecris une fonction getStatusStyles qui retourne un objet de valeurs de style inline par statut. Les etapes completees utilisent un fond accent tinte, l'etape courante utilise l'accent plein, et les etapes a venir utilisent un melange de bordure assourdie. Lire depuis les variables CSS signifie que la meme fonction fonctionne sur tous les presets de theme.

    function getStatusStyles(status: PathStep["status"]) {
      switch (status) {
        case "completed":
          return {
            iconBg: "color-mix(in srgb, var(--color-accent) 15%, transparent)",
            iconColor: "var(--color-accent)",
          };
        case "current":
          return {
            iconBg: "var(--color-accent)",
            iconColor: "var(--color-background)",
          };
        case "upcoming":
          return {
            iconBg: "color-mix(in srgb, var(--color-border) 50%, transparent)",
            iconColor: "var(--color-foreground-light)",
          };
      }
    }
  3. Echelonner l'entree avec Framer Motion

    Enveloppe chaque item dans un motion.li avec une opacite/scale initiale et un delai base sur l'index. Utilise l'ease custom [0.16, 1, 0.3, 1] pour un effet spring sans depassement. Pour la ligne de connexion, ajoute une second motion.div avec une entree scaleX et un delai legerement plus long pour qu'elle se dessine apres son badge d'etape precedent.

    <motion.li
      initial={{ opacity: 0, scale: 0.9 }}
      animate={{ opacity: 1, scale: 1 }}
      transition={{ delay: i * 0.1, duration: 0.4, ease: [0.16, 1, 0.3, 1] }}
    >
      {/* step content */}
      {!isLast && (
        <motion.div
          initial={{ scaleX: 0 }}
          animate={{ scaleX: 1 }}
          transition={{ delay: i * 0.1 + 0.2, duration: 0.3 }}
          style={{ width: "20px", height: "2px", transformOrigin: "left" }}
        />
      )}
    </motion.li>
  4. Ajouter l'anneau pulsant pour l'etape courante

    Dans la div du badge icone, rends conditionnellement une motion.div positionnee en absolu quand le statut est 'current'. Anime scale de 1 a 1.4 et opacity de 0.4 a 0 avec une repetition infinie. Une duree de 2 secondes garde la pulsation calme plutot que frenetique.

    {step.status === "current" && (
      <motion.div
        animate={{ scale: [1, 1.4, 1], opacity: [0.4, 0, 0.4] }}
        transition={{ duration: 2, repeat: Infinity }}
        style={{
          position: "absolute",
          inset: "-3px",
          borderRadius: "50%",
          border: "2px solid var(--color-accent)",
        }}
      />
    )}

Quand l'utiliser

Utilise ce composant dans les tunnels de paiement, les wizards d'onboarding ou les formulaires multi-etapes ou montrer le contexte de progression reduit l'anxiete de l'utilisateur. Il fonctionne particulierement bien dans les dashboards SaaS et les entonnoirs e-commerce. A eviter sur les navigations plates mono-page ou un fil d'Ariane standard avec des liens texte est plus leger et moins distrayant. Sur mobile avec beaucoup d'etapes, envisage de replier les etapes completees en simple icone pour eviter le debordement horizontal.

Utilisé par

  • Stripe, Utilise des indicateurs d'etapes visuels avec des badges icones et des etats de completion dans ses tunnels de paiement et d'onboarding.
  • Linear, Emploie une navigation consciente de la progression dans ses wizards de configuration de projet, avec une differentiation visuelle entre etapes completees et actives.
  • Shopify, Le tunnel de paiement utilise des fils d'Ariane a etapes avec icones pour guider marchands et acheteurs dans des processus multi-etapes.

FAQ

Comment ajouter plus d'icones a la map d'icones ?

Importe n'importe quelle icone Lucide en haut du fichier et ajoute-la a l'objet iconMap avec une cle string. Passe ensuite cette cle comme prop icon dans ton tableau de steps. Aucun autre changement necessaire.

Peut-on l'utiliser comme stepper plutot que breadcrumb ?

Le composant se comporte deja visuellement comme un stepper. Pour une semantique de stepper pure, remplace les elements <a> par des <button> et pilote l'etape active avec de l'etat local plutot que la navigation par href.

L'animation rejoue-t-elle quand la prop steps change ?

Par defaut Framer Motion ne joue l'entree qu'une fois par montage. Pour rejouer a chaque changement de donnees, ajoute une prop key basee sur le tableau steps a l'element <ol> pour que React le remonte a chaque mise a jour.

Y a-t-il un risque de mismatch d'hydratation avec le SSR ?

Le composant utilise la directive 'use client' et ne contient aucune valeur aleatoire ou basee sur la date, donc les rendus serveur et client produisent un balisage identique. Aucune garde SSR speciale n'est necessaire.

"use client";

import { motion } from "framer-motion";
import { Home, Package, Settings, CheckCircle, Circle, ChevronRight } from "lucide-react";
import React from "react";

interface PathStep {
  label: string;
  href?: string;
  icon?: string;
  status: "completed" | "current" | "upcoming";
}

interface BreadcrumbPathVisualProps {
  steps?: PathStep[];
}

const iconMap: Record<string, React.ElementType> = {
  Home,
  Package,
  Settings,
  CheckCircle,

Code complet réservé à Pro

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

Passer en Pro, 9,99€/mois

Avis

Breadcrumb React avec icones et statut de progression,