React + MotionNavigation

Zusammenklappende Breadcrumb

Die Brotkrumen schrumpfen zu Icons und zeigen beim Überfahren oder Fokussieren federnd ihren Namen; tiefere Ebenen bleiben blass sichtbar.

Einstellungen

0

Code

import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Box, Folder, House, Layers, Palette } from "lucide-react";
import type { LucideIcon } from "lucide-react";

const CRUMB_PATH: { label: string; icon: LucideIcon }[] = [
  { label: "Start", icon: House },
  { label: "Projekte", icon: Folder },
  { label: "Aimran", icon: Box },
  { label: "Design", icon: Palette },
  { label: "Navigation", icon: Layers },
];

const CRUMB_SPRING = { type: "spring", stiffness: 460, damping: 36 } as const;

interface CollapsingBreadcrumbProps {
  visible?: number;
  accent?: string;
}

export default function CollapsingBreadcrumb({
  visible = 0,
  accent = "#0070f3",
}: CollapsingBreadcrumbProps) {
  const [depth, setDepth] = useState(CRUMB_PATH.length - 1);
  const [peek, setPeek] = useState<number | null>(null);

  return (
    <nav aria-label="Brotkrumen" className="max-w-full">
      <motion.ol
        layout
        transition={CRUMB_SPRING}
        onPointerLeave={() => setPeek(null)}
        className="flex h-12 max-w-full items-center rounded-full bg-white px-1.5 text-[13px] text-[#1d1d1f] shadow-[0_1px_2px_rgba(0,0,0,0.04),0_10px_32px_rgba(0,0,0,0.07)] ring-1 ring-black/[0.06] dark:bg-[#1c1c1e] dark:text-[#f5f5f7] dark:shadow-[0_10px_32px_rgba(0,0,0,0.4)] dark:ring-white/10"
      >
        {CRUMB_PATH.map((crumb, i) => {
          const Icon = crumb.icon;
          const current = i === depth;
          const ahead = i > depth;
          const named = current || (i < depth && i >= depth - visible) || peek === i;
          return (
            <motion.li
              key={crumb.label}
              layout
              transition={CRUMB_SPRING}
              className="flex min-w-0 items-center"
            >
              {i > 0 && (
                <span
                  aria-hidden
                  className="select-none px-0.5 text-[16px] font-light text-black/15 dark:text-white/20"
                >
                  /
                </span>
              )}
              <button
                type="button"
                onClick={() => setDepth(i)}
                onPointerEnter={() => setPeek(i)}
                onFocus={() => setPeek(i)}
                onBlur={() => setPeek(null)}
                aria-current={current ? "page" : undefined}
                aria-label={ahead ? "Zurück zu " + crumb.label : crumb.label}
                className={
                  "group flex h-9 min-w-9 items-center justify-center rounded-full px-2 outline-none transition-[background-color,color,opacity] duration-200 focus-visible:ring-2 active:scale-[0.96] " +
                  (current
                    ? "font-medium"
                    : "text-[#86868b] hover:bg-black/[0.04] hover:text-[#1d1d1f] dark:hover:bg-white/[0.07] dark:hover:text-[#f5f5f7]") +
                  (ahead ? " opacity-40 hover:opacity-100 focus-visible:opacity-100" : "")
                }
                style={{ ["--tw-ring-color" as string]: accent + "66" }}
              >
                <Icon
                  className="h-4 w-4 shrink-0"
                  strokeWidth={1.5}
                  style={{ color: current ? accent : undefined }}
                />
                <AnimatePresence initial={false}>
                  {named && (
                    <motion.span
                      key="label"
                      initial={{ width: 0, opacity: 0, filter: "blur(3px)" }}
                      animate={{ width: "auto", opacity: 1, filter: "blur(0px)" }}
                      exit={{ width: 0, opacity: 0, filter: "blur(3px)" }}
                      transition={CRUMB_SPRING}
                      className="block overflow-hidden whitespace-nowrap"
                    >
                      <span className="block max-w-[8.5rem] truncate pl-1.5">{crumb.label}</span>
                    </motion.span>
                  )}
                </AnimatePresence>
              </button>
            </motion.li>
          );
        })}
      </motion.ol>
    </nav>
  );
}

Prompt für KI

Füg ihn in ChatGPT, Claude oder Cursor ein und der Baustein wird mit diesen Einstellungen an dein Projekt angepasst, auch ohne React.

Mehr aus Navigation

Wofür du ihn nutzen kannst

Tiefe Pfade fressen schnell Platz: ein Dateimanager, ein Hilfecenter mit Bereichen in Bereichen, eine Shop-Kategorie wie Start / Damen / Schuhe / Sneaker. Diese Breadcrumb-Navigation in React zeigt nur die aktuelle Seite mit Namen, der Rest bleibt Icon. Springst du nach oben, bleiben die verlassenen Ebenen blass stehen, damit du zurückkannst.

Auf Touchscreens gibt es kein Hover, die Namen erscheinen erst beim Antippen. Sind deine Icons nicht eindeutig, stell „Eltern mit Namen“ auf eins oder zwei. Und nimm Icons, die jeder kennt: ein Haus für Start, einen Ordner für Projekte.