Tips & Tricks (Actualizado: 2/6/2026)

Breadcrumbs accesibles con Claude Code

Implementa breadcrumbs con Claude Code, JSON-LD, aria-current, CSS móvil y pruebas en React/Astro.

Breadcrumbs accesibles con Claude Code

Los breadcrumbs parecen una línea pequeña encima del título, pero en producción conectan arquitectura del sitio, enlaces internos, accesibilidad, datos estructurados y diseño móvil. Una implementación débil puede verse bien y aun así ocultar la página actual a lectores de pantalla, enviar JSON-LD inválido a Google o empujar la introducción hacia abajo en teléfonos.

Cuando probé este patrón en plantillas de ClaudeCodeLab, el primer borrador de Claude Code dibujó Home > Blog > Title, pero olvidó aria-current, usó URLs relativas en JSON-LD, se rompió en móvil y mostró slugs sin editar. Claude Code puede corregirlo, siempre que el prompt defina el contrato desde el principio.

Esta guía explica cómo pedir a Claude Code que genere y revise breadcrumbs accesibles para sitios React, Next.js-like y Astro. Léela junto con optimización SEO, accesibilidad, Astro y React.

Contrato de diseño

Un breadcrumb no reemplaza el botón atrás del navegador. Muestra jerarquía, permite volver a páginas padre y ayuda a los motores de búsqueda a entender relaciones. El Breadcrumb Pattern de WAI-ARIA APG recomienda usar una región de navegación con etiqueta y aria-current="page" para la página actual.

Para datos estructurados, sigue schema.org BreadcrumbList. Cada elemento necesita position para que el orden sea claro. Si buscas presencia en Google Search, revisa también la documentación oficial de breadcrumb structured data.

DecisiónQué definirFallo común
EtiquetasTítulos, categorías o diccionarioAparecen slugs crudos
URLsEnlaces HTML y URLs absolutas para JSON-LDDatos estructurados con rutas relativas
Página actualEnlace o texto para el último itemSolo se marca por color
MóvilMostrar todo o contraer el centroEl breadcrumb ocupa varias líneas
IdiomasPrefijo y etiquetas localesSe mezclan idiomas

Prompt para Claude Code

Implementa breadcrumbs para un sitio React/Next.js o Astro.
Requisitos:
- Recibir items como { label: string; href: string }[].
- Añadir aria-current="page" al último item.
- Usar nav aria-label="Breadcrumb".
- Marcar separadores con aria-hidden="true".
- Generar JSON-LD BreadcrumbList desde el mismo array items.
- Convertir URLs de JSON-LD a absolutas usando siteUrl.
- Crear un helper para construir items desde pathname.
- Convertir slugs en texto legible y permitir override con diccionario.
- En móvil, ocultar items intermedios y mantener legible la página actual.
- Añadir pruebas Vitest para root, rutas profundas, labels localizados y query strings.
- Al final, listar checks de accesibilidad y datos estructurados.

Este prompt convierte a Claude Code en un asistente de implementación revisable. Para cambios mayores, haz una segunda pasada con la lista de revisión.

Componente React

Crea components/Breadcrumb.tsx. Pasa siteUrl sin slash final. La misma lista items alimenta la UI visible y el JSON-LD.

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 rutas

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

En Next.js usa params, metadata de CMS o frontmatter como fuente de verdad. En Astro puedes combinar Astro.url.pathname con el título del contenido.

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

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

export default async function ArticlePage() {
  const pathname = "/es/blog/claude-code-breadcrumb-navigation";
  const labels = {
    "/": "Inicio",
    "/es": "Español",
    "/es/blog": "Artículos",
    "/es/blog/claude-code-breadcrumb-navigation":
      "Breadcrumbs accesibles con Claude Code",
  };
  const items = buildBreadcrumbs(pathname, labels);

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

CSS móvil

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

Pruebas

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("/es/blog/claude-code-breadcrumb-navigation", {
        "/": "Inicio",
        "/es": "Español",
        "/es/blog": "Artículos",
        "/es/blog/claude-code-breadcrumb-navigation": "Breadcrumbs accesibles",
      }),
    ).toEqual([
      { label: "Inicio", href: "/" },
      { label: "Español", href: "/es" },
      { label: "Artículos", href: "/es/blog" },
      { label: "Breadcrumbs accesibles", href: "/es/blog/claude-code-breadcrumb-navigation" },
    ]);
  });
});

En E2E revisa nav[aria-label], un solo aria-current="page", JSON-LD parseable, URLs absolutas y ausencia de solapamiento en móvil. Continúa con la guía de Playwright.

Casos de uso

Primero, blogs y documentación: Inicio > Artículos > Claude Code > Título ayuda a volver a temas superiores y mejora el descubrimiento interno.

Segundo, ecommerce y formación de pago: Inicio > Formación > Claude Code > Taller de equipo conecta tutoriales con formación y consultoría.

Tercero, SaaS y paneles internos: Organización > Proyecto > Ajustes > Facturación reduce errores en pantallas sensibles.

Cuarto, sitios multilingües: prefijo de ruta, etiqueta visible y name de JSON-LD deben estar localizados juntos.

Errores frecuentes

Evita marcar la página actual solo con color, usar URLs relativas en JSON-LD, mostrar slugs como texto final, dejar que el breadcrumb ocupe varias líneas en móvil y mantener arrays separados para UI y datos estructurados.

Antes de publicar, comprueba aria-label, aria-current, separadores ocultos, BreadcrumbList, posiciones desde 1, URLs absolutas, consistencia visual/JSON-LD, móvil, idioma correcto y validación en Rich Results Test o Search Console.

CTA y verificación

Un breadcrumb pequeño puede apoyar la conversión de un sitio de contenidos. En ClaudeCodeLab ayuda a llevar lectores hacia la hoja gratuita, productos y formación/consultoría de Claude Code. Si tu equipo quiere adaptar prompts, checklist y revisión a su repositorio, la consultoría es el siguiente paso.

Verifiqué el código separando componente React, helper de rutas y pruebas Vitest. La decisión más útil fue generar UI y JSON-LD desde el mismo items; en un borrador anterior, dos arrays se desincronizaron tras cambiar una categoría.

Resumen

Un breadcrumb accesible es más que poner símbolos entre enlaces. Pide a Claude Code etiquetas, rutas, aria-current, JSON-LD, URLs absolutas, comportamiento móvil y pruebas, y revisa el resultado contra las fuentes oficiales antes de publicar.

#Claude Code #breadcrumb #navigation #structured data #UX
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.