# NavLink

> A navigation link that auto-detects and styles the current route, with prefix matching, external links and a collapsible NavGroup.

URL: https://apogee.avaui.dev/docs/nav-link
Last updated: 2026-10-15

A navigation link that auto-detects and styles the current route, with prefix matching, external links and a collapsible NavGroup.

Last updated October 15, 2026

```astro
<NavLink href="/docs">Docs</NavLink>
<NavLink href="/pricing">Pricing</NavLink>
<NavLink href="/about" active>About</NavLink>
```

## Add

```sh
npx @ava-ui/apogee add nav-link
```

Uses `@lucide/astro`. `NavGroup` lives in the same folder and is copied with it.

## Usage

```astro
---
import NavLink from '@/components/apogee/NavLink/NavLink.astro'
---
<NavLink href="/docs">Docs</NavLink>
```

The active state is automatic: it compares `Astro.url.pathname` to `href` (trailing slashes normalized), so the current page’s link lights up with no extra markup. `match="prefix"` also lights a section link on its child pages. Pass `active` to override.

## API

`@composable` — exposed to Content Editors in AVA. Any other native `<a>` attribute passes through (`...rest`).

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `href` | `string` | — | Link target. |
| `active` | `boolean` | auto-detected | Forces the active state. Default compares the current URL’s pathname to `href`. |
| `match` | `'exact' \| 'prefix'` | `'exact'` | `prefix` also marks `/docs` active on `/docs/button`; `/` only ever matches itself. |
| `external` | `boolean` | auto from `href` | Opens in a new tab (`target`, `rel`) with a trailing icon and a screen-reader note. Auto-detected for `http` hrefs; pass `false` to opt out. |
| `externalLabel` | `string` | `'(opens in a new tab)'` | Screen-reader text after an external link. |
| `class` | `string` | — | Extra classes, merged last. |

## States

```astro
<NavLink href="/docs">Inactive</NavLink>
<NavLink href="/docs" active>Active</NavLink>
```

-   **Inactive** (default) — muted text, brightens on hover.
-   **Active** — `aria-current="page"` and full-contrast text; auto-detected from the URL, or forced via `active`.
-   **Focus** — a visible `focus-visible` ring.

## Matching

`match="prefix"` on a section link. This page is `/docs/nav-link`, so the `/docs` link is active and the `/` link is not:

```astro
<NavLink href="/docs" match="prefix">Docs</NavLink>
<NavLink href="/" match="prefix">Home</NavLink>
```

## External links

An `http` href opens in a new tab with a trailing icon:

```astro
<NavLink href="https://astro.build">Astro</NavLink>
```

## NavGroup

A collapsible group on native `<details>`. It opens on load when a child is the current page:

```astro
<NavGroup label="Docs">
<BookOpen slot="start" />
<NavLink href="/docs/nav-link">NavLink</NavLink>
<NavLink href="/docs/navbar">Navbar</NavLink>
</NavGroup>
<NavGroup label="Projects">
<FolderKanban slot="start" />
<NavLink href="#">Spring launch</NavLink>
</NavGroup>
```

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | — | The summary row’s text. |
| `open` | `boolean` | auto | Force open or closed; by default the group opens when it contains the current page. |
| `class` | `string` | — | Extra classes on the `<details>`. |

## Slots

`start` and `end` take an icon, badge or count. `end` is pushed to the far edge when the link fills its width (a sidebar) and sits inline in a horizontal navbar.

```astro
<NavLink href="#"><Inbox slot="start" /> Inbox <Badge slot="end" size="small">12</Badge></NavLink>
```

## Examples

A link row, built for use inside `Navbar`’s default slot:

```astro
<NavLink href="/docs">Docs</NavLink>
<NavLink href="/pricing">Pricing</NavLink>
<NavLink href="/blog">Blog</NavLink>
```

## Accessibility

-   Real `<a>` — full keyboard + AT support for free.
-   `aria-current="page"` is set on the active link, so assistive tech announces it as the current page (not just visually distinct).
-   Focus ring is always visible on keyboard focus.

## Tokens

| Token | Used for |
| --- | --- |
| `--foreground-neutral` | Active link text |
| `--foreground-neutral-faded` | Inactive link text |
| `--outline-color-focus` | Focus ring |

## Do / Don’t

-   **Do** let the active state auto-detect — only pass `active` when the route can’t be matched by pathname (e.g. a hash-based section link).
-   **Do** use NavLink for site navigation, inside `Navbar` or a `Sidebar`.
-   **Don’t** use NavLink for an action — use `Button`.
-   **Don’t** hard-code the active state on every page; that defeats the point of auto-detection and drifts out of sync.

## Content

-   Labels are nouns, sentence case, one or two words (“Docs”, “Pricing”).
-   No ending punctuation.

## Related

[

LinkAn inline text link — for a link that should look like a button, use Button with href instead.

](https://apogee.avaui.dev/docs/link)[

NavbarA responsive site header that collapses its links into a mobile panel below the md breakpoint.

](https://apogee.avaui.dev/docs/navbar)[

SidebarA vertical navigation aside, sticky and full-height on desktop, collapsible behind a toggle on mobile.

](https://apogee.avaui.dev/docs/sidebar)[

BreadcrumbsA path trail showing where the current page sits in the site hierarchy.

](https://apogee.avaui.dev/docs/breadcrumbs)
