Breadcrumbs
Breadcrumbs show where this page sits, not how you got here. They are hierarchy made visible, and on our event pages they are also the main internal-linking structure search engines read.
Anatomy
Four levels is the ceiling. The last item is the current page: it is not a link, it carries aria-current="page", and it is never truncated — it is the only item that tells you where you are.
Collapsed
Past four levels, collapse the middle and keep the first and last two. The ellipsis is a real button that expands in place; it is never a link to nowhere.
Narrow screens
Below md, one level: the parent, as a back affordance. A wrapped four-level trail costs two lines and tells a phone user nothing they cannot get from the back button.
Specification
| Property | Value | Why |
|---|---|---|
| Element | <nav aria-label="Breadcrumb"> wrapping <ol> | Ordered, because the order is the hierarchy |
| Type | --text-sm, weight 400 | Orientation, not content — it never competes with the h1 |
| Colour | --color-text-secondary; current item --color-text-primary | The current item is the one you are looking for |
| Separator | Lucide chevron-right, 14px, aria-hidden | Decoration — a screen reader reading “slash” four times is noise |
| Current item | aria-current="page", not a link | A link to the page you are on is a dead control |
| Max levels | 4 shown, middle collapsed beyond that | Past four, nobody reads the middle |
| Target | 44px row on touch | Small type still needs a full-size target |
| Truncation | Middle items only, at max-width with an ellipsis | Never the current item, never the root |
Structure
<nav aria-label="Breadcrumb">
<ol class="breadcrumbs">
<li><a href="/events">Events</a></li>
<li><a href="/events/pt">Portugal</a></li>
<li><a href="/events/pt/lisboa">Lisboa</a></li>
<!-- current page: no href, no link semantics -->
<li><a aria-current="page">Maratona de Lisboa 2026</a></li>
</ol>
</nav>The separator is drawn by CSS on li + li::before so it cannot end up in the accessibility tree or in copied text. If you inline the icon instead, it needs aria-hidden="true".
Structured data
Event pages are our search surface, so the trail is emitted as BreadcrumbList alongside the markup. The JSON and the visible trail must list the same items in the same order — a mismatch is a manual-action risk, not a cosmetic one.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Events", "item": "https://sportingscouter.com/events" },
{ "@type": "ListItem", "position": 2, "name": "Portugal", "item": "https://sportingscouter.com/events/pt" },
{ "@type": "ListItem", "position": 3, "name": "Lisboa", "item": "https://sportingscouter.com/events/pt/lisboa" },
{ "@type": "ListItem", "position": 4, "name": "Maratona de Lisboa 2026" }
]
}
</script>The last entry has a name and no item, matching the visible trail, where the last entry has text and no href.
Rules
- Hierarchy, never history. If someone reaches an event from a search result, the trail still reads Events → Portugal → Lisboa. Breadcrumbs that reflect the journey are a different component, and one we do not have.
- Every level must be a real, reachable page. A crumb that 404s or lands on an empty listing is worse than a shorter trail — and “Lisboa” must list Lisbon events, not filter to nothing.
- Never the only way back. Breadcrumbs supplement navigation; they do not replace it.
- Do not repeat the h1. The current item and the page title say the same thing; that is expected and correct, but it means the trail must not be styled to compete with it.
- One trail per page. If a page belongs to two hierarchies, pick the canonical one — the same one the structured data and the canonical URL use.
theme.css.