Overview
The Navigator type provides programmatic control over navigation and browser history. Use it to navigate between routes, go back/forward, and check navigation state from within components and event handlers.
Getting a Navigator
Using the Hook
use dioxus::prelude::*;
#[derive(Clone, Routable, PartialEq)]
enum Route {
#[route("/")]
Home {},
#[route("/settings")]
Settings {},
}
#[component]
fn Home() -> Element {
let navigator = use_navigator();
rsx! {
button {
onclick: move |_| {
navigator.push(Route::Settings {});
},
"Go to Settings"
}
}
}
#[component]
fn Settings() -> Element {
rsx! { h1 { "Settings" } }
}
Direct Access
You can also get a navigator without using the hook:
use dioxus_router::navigator;
let nav = navigator();
nav.push(Route::Home {});
Both methods panic if called outside of a Router context.
Navigation Methods
push
Navigate to a new location, adding it to the history stack:
let navigator = use_navigator();
// Navigate to a route variant
navigator.push(Route::About {});
// Navigate to a path string
navigator.push("/about");
// Navigate to an external URL
navigator.push("https://dioxuslabs.com");
target
impl Into<NavigationTarget>
required
The target to navigate to. Can be:
- A route enum variant
- A string path
- An external URL
Returns: Option<ExternalNavigationFailure> - Returns an error if external navigation is not supported by the current history provider.
replace
Replace the current location without adding to history:
let navigator = use_navigator();
// Replace current route
navigator.replace(Route::Login {});
// User cannot go back to the previous page
target
impl Into<NavigationTarget>
required
The target to navigate to.
Returns: Option<ExternalNavigationFailure>
go_back
Navigate to the previous page in history:
let navigator = use_navigator();
rsx! {
button {
onclick: move |_| navigator.go_back(),
"Back"
}
}
Fails silently if there is no previous location.
go_forward
Navigate to the next page in history:
let navigator = use_navigator();
rsx! {
button {
onclick: move |_| navigator.go_forward(),
"Forward"
}
}
Fails silently if there is no next location.
can_go_back
Check if there is a previous page to navigate to:
let navigator = use_navigator();
let can_go_back = navigator.can_go_back();
rsx! {
button {
disabled: !can_go_back,
onclick: move |_| navigator.go_back(),
"Back"
}
}
Returns: bool
can_go_forward
Check if there is a next page to navigate to:
let navigator = use_navigator();
let can_go_forward = navigator.can_go_forward();
rsx! {
button {
disabled: !can_go_forward,
onclick: move |_| navigator.go_forward(),
"Forward"
}
}
Returns: bool
Navigation Targets
The NavigationTarget enum represents where to navigate:
pub enum NavigationTarget<R = String> {
Internal(R), // Internal route
External(String), // External URL
}
You rarely need to construct these manually, as they’re created automatically from routes and strings:
let navigator = use_navigator();
// These all create NavigationTarget internally:
navigator.push(Route::Home {}); // Internal
navigator.push("/about"); // Internal
navigator.push("https://example.com"); // External
Common Patterns
#[component]
fn CreatePost() -> Element {
let navigator = use_navigator();
let mut title = use_signal(|| String::new());
let submit = move |_| {
// Save post logic...
let post_id = 42;
// Navigate to the new post
navigator.push(Route::Post { id: post_id });
};
rsx! {
form { onsubmit: submit,
input {
value: "{title}",
oninput: move |e| title.set(e.value())
}
button { "Create" }
}
}
}
Conditional Navigation
#[component]
fn ProtectedPage() -> Element {
let navigator = use_navigator();
let is_authenticated = use_signal(|| false);
use_effect(move || {
if !is_authenticated() {
navigator.replace(Route::Login {});
}
});
rsx! {
h1 { "Protected Content" }
}
}
Navigation History Controls
#[component]
fn HistoryControls() -> Element {
let navigator = use_navigator();
rsx! {
div { class: "history-controls",
button {
disabled: !navigator.can_go_back(),
onclick: move |_| navigator.go_back(),
"← Back"
}
button {
disabled: !navigator.can_go_forward(),
onclick: move |_| navigator.go_forward(),
"Forward →"
}
}
}
}
Navigation with Confirmation
#[component]
fn UnsavedChanges() -> Element {
let navigator = use_navigator();
let has_unsaved_changes = use_signal(|| true);
let navigate_away = move |_| {
if has_unsaved_changes() {
let confirmed = web_sys::window()
.unwrap()
.confirm_with_message("You have unsaved changes. Leave anyway?")
.unwrap();
if confirmed {
navigator.push(Route::Home {});
}
} else {
navigator.push(Route::Home {});
}
};
rsx! {
button { onclick: navigate_away, "Leave Page" }
}
}
Redirect After Timeout
#[component]
fn SuccessMessage() -> Element {
let navigator = use_navigator();
use_effect(move || {
spawn(async move {
tokio::time::sleep(Duration::from_secs(3)).await;
navigator.push(Route::Home {});
});
});
rsx! {
div { class: "success",
"Success! Redirecting..."
}
}
}
NavigationTarget Conversion
The following types can be converted into NavigationTarget:
- Route enum variants:
Route::Home {}
- String slices:
"/about"
- Strings:
String::from("/about")
- External URLs:
"https://example.com"
// All of these work:
navigator.push(Route::Home {});
navigator.push("/about");
navigator.push(String::from("/contact"));
navigator.push("https://dioxuslabs.com");
Error Handling
External navigation may fail if the history provider doesn’t support it:
let navigator = use_navigator();
if let Some(error) = navigator.push("https://example.com") {
println!("External navigation failed: {:?}", error);
}
Source
View the source code: packages/router/src/contexts/navigator.rs