Breadcrumbs accesibles con Claude Code
Implementa breadcrumbs con Claude Code, JSON-LD, aria-current, CSS móvil y pruebas en React/Astro.
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ón | Qué definir | Fallo común |
|---|---|---|
| Etiquetas | Títulos, categorías o diccionario | Aparecen slugs crudos |
| URLs | Enlaces HTML y URLs absolutas para JSON-LD | Datos estructurados con rutas relativas |
| Página actual | Enlace o texto para el último item | Solo se marca por color |
| Móvil | Mostrar todo o contraer el centro | El breadcrumb ocupa varias líneas |
| Idiomas | Prefijo y etiquetas locales | Se 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.
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.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Escalera de permisos de Claude Code para ampliar acceso sin perder control
Pasa de read-only a ediciones limitadas, comandos de prueba y checks de deploy con menos riesgo.
Claude Code Small PR Proof Pack: cambios pequeños que sí se pueden revisar
Un paquete de prueba para PRs de Claude Code: diff, checks, URL pública, CTA y rollback.
Gate de revisión antes del commit con Claude Code
Cómo revisar con Claude Code antes del commit: diff, build, URL pública, Gumroad, consultoría, tests y archivos ajenos.