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

How to build an animated breadcrumb with progress icons in React

A visual breadcrumb with progress status in React renders each step as an icon badge with a completed/current/upcoming state, connects them with animated lines, and staggers their entrance using Framer Motion. Three status variants drive all colors through a single getStatusStyles function that reads CSS custom properties.

  • Stack: React 18 + Framer Motion 11 + lucide-react + Tailwind v4, ~207 lines, zero extra runtime deps.
  • Animation: staggered scale + opacity entrance (0.1s delay per item) with a spring ease [0.16, 1, 0.3, 1].
  • Current step pulses with an infinite scale animation on the ring border to draw focus.
  • Accessible: rendered as <nav aria-label> + <ol> list, semantic HTML for screen readers.
  • Responsive on small screens but long label sets may overflow, clip or wrap labels below 480px.

Breadcrumb Path Visual is a React navigation component that goes beyond a plain trail of links. Each step carries an icon, a progress state, and a short animated connecting line, turning a dry page location indicator into a readable map of where the user is in a multi-step flow. The entrance stagger and the pulsing ring on the current step give it a finished, product-quality feel.

Anatomy

The component is a semantic <nav> wrapping an <ol> list. Each <li> contains an anchor with two visual pieces: a 32px circular icon badge and a text label. Completed steps also show a 12px CheckCircle badge next to the label. Between items, a small animated horizontal line (20px, scaleX entrance) plus a ChevronRight arrow act as the visual separator. All colors come from CSS custom properties, so the component adapts to any theme preset without touching the TSX.

How it works

Each list item mounts with a Framer Motion initial/animate pair (opacity 0 -> 1, scale 0.9 -> 1) and a delay of i * 0.1s so items cascade left to right. The connector line between items uses a separate motion.div with initial scaleX:0, animate scaleX:1 and a slightly later delay (i * 0.1 + 0.2s) so the line draws after the step badge appears. The pulsing ring on the current step is an absolutely-positioned motion.div that loops scale [1, 1.4, 1] and opacity [0.4, 0, 0.4] on a 2-second repeat, creating a sonar-like pulse with no JavaScript timer. The getStatusStyles function acts as the single source of truth for all three states, returning object literals that map to CSS custom property values rather than hardcoded colors.

How to build it in React

  1. Define the step data shape and icon map

    Create a PathStep interface with label, href, icon (string key), and status union type. Build an iconMap object that maps string keys to Lucide icon components. This lets mock data stay plain JSON while the component resolves icons at runtime.

    interface PathStep {
      label: string;
      href?: string;
      icon?: string;
      status: "completed" | "current" | "upcoming";
    }
    
    const iconMap: Record<string, React.ElementType> = {
      Home,
      Package,
      Settings,
      CheckCircle,
    };
  2. Map each status to CSS custom property tokens

    Write a getStatusStyles function that returns an object of inline style values per status. Completed steps use a tinted accent background, the current step uses the solid accent, and upcoming steps use a muted border mix. Reading from CSS variables means the same function works across all theme presets.

    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. Stagger the entrance with Framer Motion

    Wrap each list item in a motion.li with initial opacity/scale and an index-based delay. Use the custom ease [0.16, 1, 0.3, 1] for an overshoot-free spring feel. For the connector line, add a second motion.div with a scaleX entrance and a slightly longer delay so it draws after its preceding step badge.

    <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. Add the pulsing ring for the current step

    Inside the icon badge div, conditionally render an absolutely-positioned motion.div when status is 'current'. Animate scale from 1 to 1.4 and opacity from 0.4 to 0 with an infinite repeat. A 2-second duration keeps the pulse calm rather than frantic.

    {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)",
        }}
      />
    )}

When to use it

Reach for this component in checkout flows, onboarding wizards, or multi-step forms where showing progress context reduces user anxiety. It works especially well in SaaS dashboards and e-commerce funnels. Avoid it on flat single-page navigations where a standard breadcrumb with text links is lighter and less distracting. On mobile with many steps, consider collapsing completed steps to just an icon to avoid horizontal overflow.

Used by

  • Stripe, Uses visual step indicators with icon badges and completion states throughout its payment and onboarding flows.
  • Linear, Employs progress-aware navigation in its project setup wizards, with visual differentiation between completed and active steps.
  • Shopify, Checkout flow uses icon-driven step breadcrumbs to guide merchants and buyers through multi-stage processes.

FAQ

How do I add more icons to the icon map?

Import any Lucide icon at the top of the file and add it to the iconMap object with a string key. Then pass that key as the icon prop in your steps array. No other changes needed.

Can I use this as a stepper instead of a breadcrumb?

The component already behaves like a stepper visually. For pure stepper semantics, replace the <a> elements with <button> elements and drive the active step with local state instead of href navigation.

Does the animation replay when the steps prop changes?

By default Framer Motion only plays the entrance once per mount. To replay on data change, add a key prop based on the steps array to the <ol> element so React remounts it on each update.

Is there a risk of hydration mismatch with SSR?

The component uses the 'use client' directive and carries no random or date-based values, so server and client renders produce identical markup. No special SSR guard is needed.

"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

Reviews

React Breadcrumb with Icons and Progress Status, Tutorial