Every navigation component draws links: a navbar's destinations, a footer's groups, a
breadcrumb trail, a sidebar's sections, a pagination control. None of them render a bare
`<a>`. A bare anchor reloads the document, which throws away the state the application has
built and defeats the router above it, so each of these components lets the page state
which component to render instead.

## Two places to state it

**Per destination.** An item carries the component and its props:

```tsx
<Breadcrumb
  items={[
    { label: "Invoices", href: "/invoices", component: RouterLink, componentProps: { prefetch: true } },
    { label: "INV-1041", isCurrent: true },
  ]}
/>
```

**Per component.** A family-level `link` states it once for every destination it renders:

```tsx
<Navbar
  links={[{ label: "Campaigns", href: "/campaigns", isActive: true }]}
  link={{ component: RouterLink, props: { prefetch: true } }}
/>
```

Where both are given, the item wins: a destination that needs different props than its
siblings can say so without restating the component. The merged props are the family's
first, then the item's, so the more specific statement is the one that takes effect.

Support for the two levels is not uniform, so check the component's page:

| Component | Per destination | Once per component |
| --- | --- | --- |
| `Navbar` | `links[].component` + `componentProps` | `link={{ component, props }}` |
| `Footer` | `groups[].links[]` and `social`/`legal` items | `link={{ component, props }}` |
| `Breadcrumb` | `items[].component` + `componentProps` | `link={{ component, props }}`, with the step winning |
| `Card`, `Link`, `Image`, `Button` | | `component` + `componentProps`, or `link` |
| `Sidebar` | | `link={{ component, props }}`, merged under each item's `anchorProps` |

`Sidebar` is the one that states the link once: it renders sections of rows rather than a
list of destinations, so its `link` is the family's and each item's `anchorProps` are merged
on top of it.

## What the substitute receives

The component is rendered in place of the anchor and receives the anchor's props,
`href`, `className`, `aria-current`, the press handler, plus whatever `componentProps`
adds. A router's link is written for that shape: it takes a target, renders an anchor, and
intercepts the press.

This is the seam that makes one page description work in Next.js, Vite and TanStack Start.
The application states its router once, at the link that renders it, and the page states
destinations. See [Page compositions](/guides/page-compositions) for the same idea applied
to a whole page.

## Current, disabled and external

| State | Prop | What it does |
| --- | --- | --- |
| Current | `isActive` (items) / `isCurrent` (breadcrumb) | Marks the destination as the current page with `aria-current="page"` and the active treatment, so it is announced rather than only coloured |
| Disabled | `disabled` (items, `Link`) | `aria-disabled` and a press that is refused; the destination stays in the reading order |
| External | `isExternal` (`Link`, footer items) | Renders the external affordance and the `target`/`rel` an off-site destination needs, so a reader is told where the link goes |

A destination that is current is not a destination the reader needs to press again, which is
why `aria-current` carries that meaning rather than the colour.

## Images

The same seam exists for images, because a framework's image component knows things a bare
`<img>` does not, the intrinsic size, the loader, the allowed host. `Image`, `Card.image`
and `Avatar` take `component` and `componentProps` for exactly that reason.

```tsx
import NextImage from "next/image";

<Image
  src="/campaign.png"
  alt="The campaign"
  component={NextImage}
  componentProps={{ width: 640, height: 360 }}
/>
```

## When not to substitute

If the application does not use a client-side router, a plain Vite page, a marketing site
that reloads, leave the substitution out. The components render anchors by default, and an
anchor is the right element for a document that navigates.
