Components · Breadcrumbs
Components

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.

Maratona de Lisboa 2026

Specification

PropertyValueWhy
Element<nav aria-label="Breadcrumb"> wrapping <ol>Ordered, because the order is the hierarchy
Type--text-sm, weight 400Orientation, not content — it never competes with the h1
Colour--color-text-secondary; current item --color-text-primaryThe current item is the one you are looking for
SeparatorLucide chevron-right, 14px, aria-hiddenDecoration — a screen reader reading “slash” four times is noise
Current itemaria-current="page", not a linkA link to the page you are on is a dead control
Max levels4 shown, middle collapsed beyond thatPast four, nobody reads the middle
Target44px row on touchSmall type still needs a full-size target
TruncationMiddle items only, at max-width with an ellipsisNever 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.
Sporting Scouter Design System
Every token on this site is generated from theme.css.