Tips & Tricks (Aktualisiert: 2.6.2026)

Barrierefreie Breadcrumbs mit Claude Code

Breadcrumbs mit Claude Code, JSON-LD, aria-current, mobilem CSS und Tests für React/Astro umsetzen.

Barrierefreie Breadcrumbs mit Claude Code

Breadcrumbs wirken wie eine kleine Zeile über der Überschrift. In produktiven Websites verbinden sie aber Informationsarchitektur, interne Links, Barrierefreiheit, strukturierte Daten und mobile Darstellung. Eine schwache Umsetzung kann optisch funktionieren, während Screenreader die aktuelle Seite nicht erkennen, JSON-LD relative URLs enthält oder lange Titel auf dem Smartphone den Einstieg verdrängen.

In ClaudeCodeLab-Templates erzeugte Claude Code nach einem knappen Prompt zunächst Home > Blog > Title. Es fehlten jedoch aria-current, absolute URLs im JSON-LD, sauberes Mobile-Verhalten und menschenlesbare Labels für dynamische Slugs. Der Unterschied liegt im Prompt: Claude Code braucht den vollständigen Vertrag.

Dieser Leitfaden zeigt die Umsetzung für React, Next.js-ähnliche Sites und Astro. Passende Grundlagen sind SEO-Optimierung, Barrierefreiheit, Astro und React.

Designvertrag

Breadcrumbs ersetzen nicht den Zurück-Button. Sie zeigen Hierarchie, führen zu übergeordneten Seiten und erklären Suchmaschinen die Beziehung zwischen Seiten. Das WAI-ARIA APG Breadcrumb Pattern beschreibt eine beschriftete Navigationsregion und aria-current="page" für die aktuelle Seite.

Strukturierte Daten folgen schema.org BreadcrumbList. Jedes Element braucht eine position, damit die Reihenfolge eindeutig ist. Für Google Search ist die offizielle Dokumentation zu Breadcrumb structured data die passende Primärquelle.

EntscheidungFestlegenHäufiger Fehler
LabelsTitel, Kategorien oder WörterbuchRoh-Slugs werden angezeigt
URLsHTML-Links und absolute JSON-LD-URLsRelative Pfade in strukturierten Daten
Aktuelle SeiteLink oder Text im letzten ItemStatus nur über Farbe
MobileVollständig oder mittig gekürztMehrzeilige Breadcrumb-Leiste
SprachenPrefix und lokalisierte LabelsSprachmix in Navigation/JSON-LD

Prompt für Claude Code

Implementiere Breadcrumbs für eine React/Next.js- oder Astro-Site.
Anforderungen:
- items als { label: string; href: string }[] akzeptieren.
- Dem letzten Item aria-current="page" geben.
- nav aria-label="Breadcrumb" verwenden.
- Trenner mit aria-hidden="true" markieren.
- JSON-LD BreadcrumbList aus demselben items-Array erzeugen.
- JSON-LD-URLs mit siteUrl in absolute URLs umwandeln.
- Helper für items aus pathname hinzufügen.
- Slugs lesbar formatieren und Label-Wörterbuch erlauben.
- Auf Mobile mittlere Items ausblenden, aktuelle Seite lesbar halten.
- Vitest für Root, tiefe Pfade, lokalisierte Labels und Query Strings ergänzen.
- Danach Accessibility- und Structured-Data-Checks auflisten.

Für größere Änderungen lohnt eine zweite Prüfung mit der Claude Code Review-Checkliste.

React-Komponente

import type { ReactNode } from "react";

export type BreadcrumbItem = {
  label: string;
  href: string;
};

type BreadcrumbProps = {
  items: BreadcrumbItem[];
  siteUrl: string;
  ariaLabel?: string;
};

function toAbsoluteUrl(siteUrl: string, href: string) {
  return new URL(href, siteUrl).toString();
}

function Separator(): ReactNode {
  return (
    <span className="breadcrumb__separator" aria-hidden="true">
      /
    </span>
  );
}

export function Breadcrumb({
  items,
  siteUrl,
  ariaLabel = "Breadcrumb",
}: BreadcrumbProps) {
  if (items.length <= 1) return null;

  const jsonLd = {
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    itemListElement: items.map((item, index) => ({
      "@type": "ListItem",
      position: index + 1,
      item: {
        "@id": toAbsoluteUrl(siteUrl, item.href),
        name: item.label,
      },
    })),
  };

  return (
    <>
      <nav className="breadcrumb" aria-label={ariaLabel}>
        <ol className="breadcrumb__list">
          {items.map((item, index) => {
            const isCurrent = index === items.length - 1;
            return (
              <li className="breadcrumb__item" key={item.href}>
                {index > 0 ? <Separator /> : null}
                {isCurrent ? (
                  <span className="breadcrumb__current" aria-current="page">
                    {item.label}
                  </span>
                ) : (
                  <a className="breadcrumb__link" href={item.href}>
                    {item.label}
                  </a>
                )}
              </li>
            );
          })}
        </ol>
      </nav>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
    </>
  );
}

Routen-Helper

import type { BreadcrumbItem } from "@/components/Breadcrumb";

export type BreadcrumbLabels = Record<string, string>;

function titleize(segment: string) {
  return decodeURIComponent(segment)
    .replace(/[-_]+/g, " ")
    .replace(/\b\w/g, (char) => char.toUpperCase());
}

export function buildBreadcrumbs(
  pathname: string,
  labels: BreadcrumbLabels = {},
): BreadcrumbItem[] {
  const cleanPath = pathname.split(/[?#]/)[0].replace(/\/+$/, "") || "/";
  const segments = cleanPath.split("/").filter(Boolean);
  const items: BreadcrumbItem[] = [
    { label: labels["/"] ?? "Home", href: "/" },
  ];

  let href = "";

  for (const segment of segments) {
    href += `/${segment}`;
    items.push({
      label: labels[href] ?? labels[segment] ?? titleize(segment),
      href,
    });
  }

  return items;
}
import { Breadcrumb } from "@/components/Breadcrumb";
import { buildBreadcrumbs } from "@/lib/breadcrumbs";

const siteUrl = "https://claudecodelab.com";

export default async function ArticlePage() {
  const pathname = "/de/blog/claude-code-breadcrumb-navigation";
  const labels = {
    "/": "Start",
    "/de": "Deutsch",
    "/de/blog": "Artikel",
    "/de/blog/claude-code-breadcrumb-navigation":
      "Barrierefreie Breadcrumbs mit Claude Code",
  };
  const items = buildBreadcrumbs(pathname, labels);

  return (
    <main>
      <Breadcrumb items={items} siteUrl={siteUrl} ariaLabel="Breadcrumb" />
      <h1>Barrierefreie Breadcrumbs mit Claude Code</h1>
    </main>
  );
}

Für Astro bleibt die Datenform gleich; nutze Astro.url.pathname und gib JSON-LD mit set:html={JSON.stringify(jsonLd)} aus.

CSS, Tests und Prüfung

.breadcrumb { margin-block: 0 1rem; font-size: 0.875rem; color: #4b5563; }
.breadcrumb__list { display: flex; flex-wrap: wrap; gap: 0.25rem; list-style: none; margin: 0; padding: 0; }
.breadcrumb__item { align-items: center; display: inline-flex; min-width: 0; }
.breadcrumb__link { color: #2563eb; text-decoration: underline; text-underline-offset: 0.15em; }
.breadcrumb__current { color: #111827; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.breadcrumb__separator { color: #9ca3af; margin-inline: 0.35rem; }
@media (max-width: 640px) {
  .breadcrumb__list { flex-wrap: nowrap; }
  .breadcrumb__item:not(:first-child):not(:nth-last-child(-n + 2)) { display: none; }
  .breadcrumb__item:nth-last-child(2)::after { color: #9ca3af; content: "..."; margin-inline: 0.35rem; }
  .breadcrumb__current { max-width: 58vw; }
}
import { describe, expect, it } from "vitest";
import { buildBreadcrumbs } from "./breadcrumbs";

describe("buildBreadcrumbs", () => {
  it("returns only Home for the root path", () => {
    expect(buildBreadcrumbs("/")).toEqual([{ label: "Home", href: "/" }]);
  });

  it("builds nested breadcrumbs and ignores query strings", () => {
    expect(buildBreadcrumbs("/blog/claude-code?page=2")).toEqual([
      { label: "Home", href: "/" },
      { label: "Blog", href: "/blog" },
      { label: "Claude Code", href: "/blog/claude-code" },
    ]);
  });

  it("uses localized labels when provided", () => {
    expect(
      buildBreadcrumbs("/de/blog/claude-code-breadcrumb-navigation", {
        "/": "Start",
        "/de": "Deutsch",
        "/de/blog": "Artikel",
        "/de/blog/claude-code-breadcrumb-navigation": "Breadcrumbs",
      }),
    ).toEqual([
      { label: "Start", href: "/" },
      { label: "Deutsch", href: "/de" },
      { label: "Artikel", href: "/de/blog" },
      { label: "Breadcrumbs", href: "/de/blog/claude-code-breadcrumb-navigation" },
    ]);
  });
});

E2E prüft nav[aria-label], genau ein aria-current="page", parsebares JSON-LD, absolute URLs und Mobile-Layout. Siehe auch Playwright-Tests.

Anwendungsfälle, Risiken und CTA

Wichtige Anwendungsfälle sind Blogs/Dokumentationen, Ecommerce- und Trainingsseiten, tiefe SaaS-Einstellungen und mehrsprachige Sites. Typische Fehler sind Farb-only-Status, relative JSON-LD-URLs, rohe Slugs, kaputtes Mobile-Layout und getrennte Datenquellen für UI und JSON-LD.

Vor Veröffentlichung: aria-label, aria-current, versteckte Trenner, BreadcrumbList, position, absolute URLs, Konsistenz zwischen UI und JSON-LD, Mobile, Sprache und Search Console prüfen.

Auf ClaudeCodeLab stützen Breadcrumbs den Weg von Artikeln zur kostenlosen Checkliste, zu Produkten und zu Claude Code Training/Consulting. Ich habe die Beispiele als React-Komponente, Helper und Vitest-Test geprüft; entscheidend war eine gemeinsame items-Quelle für UI und JSON-LD.

Fazit

Gute Breadcrumbs sind keine Dekoration. Gib Claude Code Labels, Routen, aria-current, JSON-LD, absolute URLs, Mobile-Verhalten und Tests vor und reviewe das Ergebnis anhand der offiziellen Quellen.

#Claude Code #Breadcrumb #navigation #structured data #UX
Kostenlos

Kostenloses PDF: Claude-Code-Cheatsheet

E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.

Wir schützen Ihre Daten und senden keinen Spam.

Masa

Über den Autor

Masa

Engineer für praktische Claude-Code-Workflows und Team-Einführung.