Enterprise-grade navigation library for Yew — automatic active state detection and a complete component system.
🌐 Live demo → — 📖 Architectural book →
Click a NavLink — the route changes, and the active class plus aria-current="page" follow automatically.
Table of Contents
- Overview
- Quality Gates
- Installation
- Requirements
- Quick Start
- Components
- CSS Integration
- Architecture
- Examples
- API Reference
- Migration Guides
- Coverage
- Contributing
- License
Overview
yew-nav-link is a comprehensive navigation library for the Yew web framework. It provides:
| Feature | Description |
|---|---|
| NavLink | Drop-in replacement for Yew Router's <Link> with automatic active class detection |
| Component System | 15+ ready-to-use UI components (tabs, dropdowns, pagination, badges, icons) |
| Hooks | Reactive hooks for route state, active checking, breadcrumbs, and programmatic navigation |
| Utilities | Path manipulation, URL encoding, keyboard navigation, and query string handling |
| Customization | Custom CSS classes, programmatic navigation, and extensible breadcrumb providers |
The core NavLink component eliminates manual active state tracking. It compares the current route against the target on every render and applies the active CSS class automatically — zero configuration required.
Quality Gates
Every gate below runs in CI and blocks merge on failure — no advisory-only checks. This table is the fast path for reviewers: each quality dimension maps to the tool that enforces it and the workflow that runs it.
| Dimension | Enforced by | Workflow |
|---|---|---|
| Unit + doctests | cargo nextest + cargo test --doc, across MSRV / stable / nightly on Linux, macOS, Windows |
ci.yml · test, check |
| Browser tests | wasm-bindgen-test headless on Chrome and Firefox |
ci.yml · wasm_tests |
| End-to-end tests | Playwright against the trunk-built demo (Chromium + Firefox) | ci.yml · e2e |
| Property testing | proptest over path / URL / query invariants |
ci.yml · test |
| Fuzzing | cargo-fuzz, 5 targets (path join/normalize, URL round-trip, query params, URL parts) |
fuzz.yml |
| Mutation testing | cargo-mutants: full run nightly + diff-scoped pass per PR |
mutants.yml |
| Coverage control | cargo-llvm-cov → Codecov, 95 % project + patch gate |
ci.yml · coverage |
| Static analysis | clippy -D warnings (all + no-default features) · CodeQL SAST · zizmor over the workflows themselves |
ci.yml · check · codeql.yml · zizmor.yml |
| Supply chain | cargo-deny, cargo-audit, cargo-machete, cargo-udeps |
ci.yml · security |
| Security posture | OSSF Scorecard | scorecard.yml |
| API stability | cargo-semver-checks + cargo-public-api baseline diff |
ci.yml · semver_checks, public_api |
| Releases & semver | release-plz (version + changelog + publish) · signed build provenance & SBOM attestation | release-plz.yml · release-attestations.yml |
| Licensing | REUSE / SPDX compliance | ci.yml · reuse |
| Performance budgets | criterion benches · WASM size budget · Lighthouse assertions | ci.yml · benchmarks, wasm-build, lighthouse |
| Formatting & workflows | cargo +nightly fmt --check · actionlint · PR-title format gate |
ci.yml · fmt, actionlint, pr_title |
Installation
[]
= "0.12"
Requirements
| Dependency | Version |
|---|---|
| Rust | 1.96+ |
| Edition | 2024 |
| Yew | 0.23+ |
| yew-router | 0.20+ |
Quick Start
Component Syntax
use *;
use NavLink;
use *;
When the user visits /about, the second link automatically receives class="nav-link active".
Function Syntax
use *;
use ;
use *;
Partial Matching
Keep parent links highlighted on nested routes:
html!
Partial matching is segment-aware: /docs matches /docs/api but not /documentation.
Custom CSS Classes
Customize the default nav-link and active classes:
html!
Programmatic Navigation
use_navigation::<R>() returns a [Navigation<R>] handle exposing pre-built Callbacks — no manual Callback::from(...) boilerplate.
use *;
use use_navigation;
Custom Breadcrumb Providers
Implement [BreadcrumbLabelProvider] to control how each path segment is rendered. The provider operates on paths (e.g. /docs/api), not on Routable enum variants — it works the same for static and parameterised routes.
use Rc;
use ;
;
Components
Core Navigation
| Component | Purpose |
|---|---|
NavLink<R> |
Navigation link with automatic active state |
[NavList] |
Accessible navigation list container (<ul> with ARIA) |
[NavItem] |
Navigation list item (<li>) |
[NavDivider] |
Visual separator between navigation groups |
UI Components
| Component | Purpose |
|---|---|
[NavBadge] |
Badge/counter for navigation items |
[NavHeader] |
Section header for navigation groups |
[NavText] |
Plain text element within navigation |
[NavIcon] |
Icon with configurable size |
[NavLinkWithIcon] |
Link with integrated icon |
[NavDropdown] |
Dropdown menu with items and dividers |
[NavTabs] |
Tabbed navigation container |
[NavTab] |
Individual tab with active state |
[NavTabPanel] |
Content panel for tabs |
[Pagination] |
Page navigation controls |
[PageItem] |
Individual page indicator |
[PageLink] |
Clickable page link |
Hooks
| Hook | Returns | Description |
|---|---|---|
use_route_info::<R>() |
Option<R> |
Currently matched route, or None when nothing matches |
use_is_active(route) |
bool |
Whether the given route is currently active |
use_is_exact_active(route) |
bool |
Whether the route matches exactly |
use_is_partial_active(route) |
bool |
Whether the route is a prefix of the current path |
use_breadcrumbs::<R>() |
Vec<BreadcrumbItem<R>> |
Auto-generated breadcrumb trail from current route |
use_navigation::<R>() |
Navigation<R> |
Programmatic navigation (push, replace, go back/forward) |
use_query_params() |
QueryParams |
URL query parameters (multi-value utils::QueryParams) |
Utilities
Path helpers are re-exported at the crate root; the URL and keyboard helpers
live under the utils module (yew_nav_link::utils::…).
| Function | Path | Description |
|---|---|---|
is_absolute(path) |
crate root | Check if a path starts with / |
join_paths(a, b) |
crate root | Join two path segments safely |
normalize_path(path) |
crate root | Collapse duplicate slashes and resolve ./..; a single trailing slash is preserved |
urlencoding_encode(s) |
utils:: |
Percent-encode a string for URLs |
urlencoding_decode(s) |
utils:: |
Decode a percent-encoded string, + becomes a space (None on invalid UTF-8) |
percent_decode(s) |
utils:: |
Decode %XX sequences keeping + literal — for path components (None on invalid UTF-8) |
handle_arrow_key(config, key) |
utils:: |
Keyboard navigation handler |
handle_home_end(config, key) |
utils:: |
Home/End key handler for navigation |
CSS Integration
Bootstrap 5
Works out of the box — nav-link and active are native Bootstrap classes.
to={Route::Home}>{ "Home" }>
<!-- Renders: <a class="nav-link active" href="/">Home</a> -->
Tailwind CSS
Define your own nav-link and active styles:
}
}
Architecture
yew-nav-link
├── active_link # Core NavLink component + Match enum
├── nav # Primitives: NavList, NavItem, NavDivider
├── components # UI: Badge, Dropdown, Icon, Tabs, Pagination
├── hooks # Reactive and programmatic route/navigation helpers
├── utils # Path, URL, keyboard navigation utilities
└── errors # NavError, NavResult types
For why the crate is shaped this way — the trade-offs picked over each
alternative — see docs/ARCHITECTURE.md for the
overview and docs/adr/ for individual architecture
decision records.
Examples
A live demo is published at https://raprogramm.github.io/yew-nav-link/. It exercises every component, hook, and utility in the public API.
Run the same demo locally:
Open http://127.0.0.1:3000 (port set in example/trunk.toml).
API Reference
NavLink<R>
| Prop | Type | Default | Description |
|---|---|---|---|
to |
R: Routable |
required | Target route |
children |
Children |
required | Link content |
partial |
bool |
false |
Enable prefix matching (a root route matches only the root path) |
class |
AttrValue |
"nav-link" |
Custom CSS class (replaces default) |
active_class |
AttrValue |
"active" |
Custom active state class |
Match
| Variant | Behavior |
|---|---|
Exact |
Active only on exact path match |
Partial |
Active when current path starts with target (segment-wise) |
nav_link<R> Function
BreadcrumbItem
Project documentation
| File | Purpose |
|---|---|
| Architectural book | Rendered mdBook of the documents below — search, syntax-highlighting, navigation. Source lives under docs/. |
docs/REQUIREMENTS.md |
Functional and non-functional requirements (what the crate does, the constraints under which it does it) |
docs/ARCHITECTURE.md |
Module layout, the active-state algorithm, hook contracts, breadcrumb context flow |
docs/ROADMAP.md |
Trajectory through 0.10.x (current line) toward 1.0 (API freeze) |
docs/BRANCHING.md |
Branching, commit, and merge policy enforced on main |
SECURITY.md |
Coordinated disclosure policy |
CONTRIBUTING.md |
Workflow, commit format, code standards |
Migration Guides
For a full release-by-release log, see CHANGELOG.md.
| From | To | Notes |
|---|---|---|
| 0.8.x | 0.9.x | Macro feature removed; component/function APIs unchanged. See CHANGELOG [0.9.0]. |
| 0.9.0 | 0.9.1 | Single-file SPA demo replaces the multi-page docs site under example/; library API unchanged. |
| 0.9.1 | 0.9.2 | BreadcrumbLabelProvider now re-exported at the crate root. Drop-in upgrade. |
| 0.10.x | 0.11.0 | use_navigation now routes push/replace/go/go_back/go_forward through the router's Navigator, so a configured basename is honored (previously ignored). Navigation<R>'s internal _marker field is no longer public — construct the handle via use_navigation::<R>(), not a struct literal. The go_back/go_forward fields and all *_callback methods keep the same signatures. |
Target: 95%+ coverage, tracked via Codecov.
Sunburst
The inner-most circle is the entire project, moving outward are folders then individual files. Size and color represent statement count and coverage.
Grid
Each block represents a single file. Size and color represent statement count and coverage.
Icicle
Top section is the entire project, proceeding through folders to individual files.
Contributing
See CONTRIBUTING.md for the contribution workflow and code standards.
License
Licensed under the MIT License.