Retour au catalogue

Header Breadcrumb

Header de page interne avec breadcrumb, titre et description. Navigation contextuelle.

headersimple Both Responsive a11y
minimalcorporateuniversalsaasstacked
Theme
"use client";

import { motion } from "framer-motion";
import { ChevronRight, Home } from "lucide-react";

interface BreadcrumbItem {
  label: string;
  href?: string;
}

interface HeaderBreadcrumbProps {
  title?: string;
  description?: string;
  breadcrumbs?: BreadcrumbItem[];
}

const ease: [number, number, number, number] = [0.16, 1, 0.3, 1];

export default function HeaderBreadcrumb({
  title = "Titre de la page",
  description = "",
  breadcrumbs = [],
}: HeaderBreadcrumbProps) {
  return (
    <section className="py-12 lg:py-16 px-6" style={{ background: "var(--color-background-alt)" }}>
      <div className="mx-auto max-w-5xl">
        {/* Breadcrumb */}
        <motion.nav
          initial={{ opacity: 0, y: -8 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.4, ease }}
          className="flex items-center gap-1.5 mb-6 text-sm"
          aria-label="Fil d'Ariane"
        >
          <a
            href="/"
            className="flex items-center gap-1 transition-colors"
            style={{ color: "var(--color-foreground-muted)", textDecoration: "none" }}
          >
            <Home size={14} />
            <span>Accueil</span>
          </a>

          {breadcrumbs.map((item, i) => (
            <span key={i} className="flex items-center gap-1.5">
              <ChevronRight size={14} style={{ color: "var(--color-foreground-light)" }} />
              {item.href && i < breadcrumbs.length - 1 ? (
                <a
                  href={item.href}
                  className="transition-colors"
                  style={{ color: "var(--color-foreground-muted)", textDecoration: "none" }}
                >
                  {item.label}
                </a>
              ) : (
                <span
                  style={{
                    color: i === breadcrumbs.length - 1 ? "var(--color-foreground)" : "var(--color-foreground-muted)",
                    fontWeight: i === breadcrumbs.length - 1 ? 500 : 400,
                  }}
                >
                  {item.label}
                </span>
              )}
            </span>
          ))}
        </motion.nav>

        {/* Title */}
        <motion.h1
          initial={{ opacity: 0, y: 16 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.6, ease, delay: 0.08 }}
          className="text-3xl md:text-4xl font-bold tracking-tight"
          style={{ color: "var(--color-foreground)" }}
        >
          {title}
        </motion.h1>

        {/* Description */}
        {description && (
          <motion.p
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ duration: 0.5, ease, delay: 0.16 }}
            className="mt-3 text-base max-w-2xl"
            style={{ color: "var(--color-foreground-muted)" }}
          >
            {description}
          </motion.p>
        )}

        {/* Separator */}
        <motion.div
          initial={{ scaleX: 0 }}
          animate={{ scaleX: 1 }}
          transition={{ duration: 0.5, ease, delay: 0.24 }}
          className="mt-8 h-px origin-left"
          style={{ background: "var(--color-border)" }}
        />
      </div>
    </section>
  );
}

Avis

Header Breadcrumb — React Header Section — Incubator