Tips & Tricks (Mis à jour: 02/06/2026)

Fil d'Ariane accessible avec Claude Code

Implémentez un fil d'Ariane avec Claude Code, JSON-LD, aria-current, CSS mobile et tests.

Fil d'Ariane accessible avec Claude Code

Le fil d’Ariane semble être une petite ligne au-dessus du titre, mais il touche en réalité à la structure du site, aux liens internes, à l’accessibilité, aux données structurées et à l’affichage mobile. Une version fragile peut paraître correcte tout en oubliant la page courante pour les lecteurs d’écran, en envoyant un JSON-LD incomplet à Google ou en cassant la mise en page sur mobile.

Dans les modèles ClaudeCodeLab, un premier prompt Claude Code a bien généré Home > Blog > Title, mais sans aria-current, avec des URL relatives dans le JSON-LD, des retours à la ligne en mobile et des slugs bruts. Claude Code est utile si on lui donne le contrat complet dès le départ.

Ce guide montre comment demander à Claude Code de générer et de relire un fil d’Ariane accessible pour React, Next.js-like et Astro. À lire avec l’optimisation SEO, l’accessibilité, Astro et React.

Contrat de conception

Un fil d’Ariane n’est pas un bouton retour. Il indique la hiérarchie, aide à revenir aux pages parentes et clarifie la relation entre pages. Le Breadcrumb Pattern du WAI-ARIA APG recommande une région de navigation libellée et aria-current="page" pour la page courante.

Les données structurées doivent suivre schema.org BreadcrumbList. Chaque élément doit avoir une position. Pour Google, vérifiez aussi la page officielle breadcrumb structured data.

DécisionÀ définirErreur fréquente
LibellésTitres, catégories ou dictionnaireSlugs affichés tels quels
URLLiens HTML et URL absolues JSON-LDChemins relatifs en données structurées
Page couranteLien ou texte finalÉtat montré seulement par la couleur
MobileTout afficher ou réduire le milieuPlusieurs lignes avant le contenu
LanguesPréfixe et libellés localisésMélange de langues

Prompt pour Claude Code

Implémente un fil d'Ariane pour un site React/Next.js ou Astro.
Exigences:
- Recevoir items comme { label: string; href: string }[].
- Ajouter aria-current="page" au dernier item.
- Utiliser nav aria-label="Fil d'Ariane".
- Marquer les séparateurs avec aria-hidden="true".
- Générer JSON-LD BreadcrumbList depuis le même tableau items.
- Convertir les URL JSON-LD en URL absolues avec siteUrl.
- Ajouter un helper qui construit items depuis pathname.
- Transformer les slugs en texte lisible et permettre un dictionnaire de labels.
- Sur mobile, masquer les items intermédiaires en gardant la page courante lisible.
- Ajouter des tests Vitest pour root, chemins profonds, labels localisés et query strings.
- Lister ensuite les vérifications accessibilité et données structurées.

Pour une modification plus large, lancez une deuxième passe avec la checklist de revue Claude Code.

Composant React

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) }}
      />
    </>
  );
}

Helper de routes

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 = "/fr/blog/claude-code-breadcrumb-navigation";
  const labels = {
    "/": "Accueil",
    "/fr": "Français",
    "/fr/blog": "Articles",
    "/fr/blog/claude-code-breadcrumb-navigation":
      "Fil d'Ariane accessible avec Claude Code",
  };
  const items = buildBreadcrumbs(pathname, labels);

  return (
    <main>
      <Breadcrumb items={items} siteUrl={siteUrl} ariaLabel="Fil d'Ariane" />
      <h1>Fil d'Ariane accessible avec Claude Code</h1>
    </main>
  );
}

Dans Astro, utilisez la même structure avec Astro.url.pathname et set:html={JSON.stringify(jsonLd)} dans un composant .astro.

CSS mobile

.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; }
}

Tests

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("/fr/blog/claude-code-breadcrumb-navigation", {
        "/": "Accueil",
        "/fr": "Français",
        "/fr/blog": "Articles",
        "/fr/blog/claude-code-breadcrumb-navigation": "Fil d'Ariane",
      }),
    ).toEqual([
      { label: "Accueil", href: "/" },
      { label: "Français", href: "/fr" },
      { label: "Articles", href: "/fr/blog" },
      { label: "Fil d'Ariane", href: "/fr/blog/claude-code-breadcrumb-navigation" },
    ]);
  });
});

En E2E, vérifiez nav[aria-label], un seul aria-current="page", un JSON-LD valide, des URL absolues et l’absence de chevauchement mobile. Voir aussi Playwright.

Cas d’usage, pièges et CTA

Les cas les plus utiles sont les blogs/documentations, les pages de formation ou ecommerce, les écrans SaaS profonds et les sites multilingues. Dans chaque cas, le fil d’Ariane améliore la compréhension du contexte et les liens internes.

Les pièges récurrents sont l’état courant indiqué seulement par couleur, les URL relatives dans JSON-LD, les slugs bruts, le mobile qui se casse et deux sources de données séparées pour l’UI et le JSON-LD. Avant publication, contrôlez aria-label, aria-current, séparateurs masqués, BreadcrumbList, position, URL absolues, cohérence visuelle/JSON-LD, mobile, langue et validation Search Console.

Sur ClaudeCodeLab, ce composant aide à guider les lecteurs vers la fiche gratuite, les produits et la formation/consulting Claude Code. J’ai vérifié le code en séparant composant React, helper et tests Vitest; la meilleure décision a été de générer l’UI et JSON-LD depuis le même items.

Résumé

Un bon fil d’Ariane n’est pas une décoration. Donnez à Claude Code les libellés, routes, aria-current, JSON-LD, URL absolues, comportement mobile et tests, puis relisez le résultat avec les sources officielles.

#Claude Code #fil d'Ariane #navigation #structured data #UX
Gratuit

PDF gratuit: cheatsheet Claude Code

Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.

Nous protégeons vos données et n'envoyons pas de spam.

Masa

À propos de l'auteur

Masa

Ingénieur spécialisé dans les workflows pratiques avec Claude Code.