Dioxus routes can extract data from URLs through path segments, query parameters, and hash fragments. All parameters are type-safe and automatically parsed.
Path Parameters
Path parameters are dynamic segments in the URL path, prefixed with : in route definitions.
Single Parameter
use dioxus::prelude::*;
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/user/:id")]
User { id: usize },
}
#[component]
fn User(id: usize) -> Element {
rsx! { h1 { "User {id}" } }
}
URL /user/123 extracts id = 123.
Multiple Parameters
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/blog/:year/:month/:slug")]
BlogPost {
year: u32,
month: u32,
slug: String,
},
}
#[component]
fn BlogPost(year: u32, month: u32, slug: String) -> Element {
rsx! {
h1 { "{slug}" }
p { "Published: {month}/{year}" }
}
}
URL /blog/2024/03/hello-world extracts:
year = 2024
month = 3
slug = "hello-world"
Supported Types
Path parameters can be any type implementing FromStr:
#[route("/user/:id")]
User { id: usize }, // Numbers
#[route("/post/:slug")]
Post { slug: String }, // Strings
#[route("/active/:enabled")]
Filter { enabled: bool }, // Booleans
#[route("/uuid/:id")]
Item { id: Uuid }, // Custom types with FromStr
Custom Types
Implement FromStr and Display for custom types:
use std::fmt;
use std::str::FromStr;
#[derive(Clone, PartialEq, Debug)]
struct UserId(usize);
impl FromStr for UserId {
type Err = std::num::ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(UserId(s.parse()?))
}
}
impl fmt::Display for UserId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
// Use in route
#[route("/user/:id")]
User { id: UserId },
Parse Errors
If parsing fails, the route doesn’t match and the router tries the next route:
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/user/:id")]
User { id: usize }, // Only matches numeric IDs
#[route("/:..path")]
NotFound { path: Vec<String> }, // Catches failed parses
}
URL /user/abc won’t match User (parse error), falls through to NotFound.
Catch-All Parameters
Capture multiple path segments with :..name:
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/files/:..path")]
Files { path: Vec<String> },
}
#[component]
fn Files(path: Vec<String>) -> Element {
let full_path = path.join("/");
rsx! { h1 { "File: {full_path}" } }
}
URL /files/docs/2024/report.pdf extracts:
path = vec!["docs", "2024", "report.pdf"]
404 Pages
Catch-all routes are perfect for 404 pages:
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/")]
Home {},
// Catches all unmatched routes
#[route("/:..path")]
NotFound { path: Vec<String> },
}
#[component]
fn NotFound(path: Vec<String>) -> Element {
rsx! {
h1 { "404: Page Not Found" }
p { "Could not find: /{path:?}" }
Link { to: Route::Home {}, "Go Home" }
}
}
Place catch-all routes last in your enum to avoid matching more specific routes.
Query Parameters
Query parameters are extracted from the URL query string after ?.
Single Query Parameter
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/search?:q")]
Search { q: String },
}
#[component]
fn Search(q: String) -> Element {
rsx! {
h1 { "Search Results" }
p { "Query: {q}" }
}
}
URL /search?q=rust extracts q = "rust".
Multiple Query Parameters
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/products?:category&:sort&:page")]
Products {
category: String,
sort: String,
page: usize,
},
}
URL /products?category=books&sort=price&page=2 extracts:
category = "books"
sort = "price"
page = 2
Optional Query Parameters
Use Option<T> for optional parameters:
#[derive(Routable, Clone, PartialEq, Debug)]
enum Route {
#[route("/search?:q&:page")]
Search {
q: String,
page: Option<usize>, // Optional parameter
},
}
#[component]
fn Search(q: String, page: Option<usize>) -> Element {
let page_num = page.unwrap_or(1);
rsx! {
h1 { "Search: {q}" }
p { "Page {page_num}" }
}
}
Both URLs work:
/search?q=rust → q = "rust", page = None
/search?q=rust&page=2 → q = "rust", page = Some(2)
Default Values
Query parameter types must implement Default:
#[derive(Clone, PartialEq, Debug)]
struct SearchOptions {
sort_by: String,
}
impl Default for SearchOptions {
fn default() -> Self {
Self {
sort_by: "relevance".to_string(),
}
}
}
impl FromStr for SearchOptions {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self { sort_by: s.to_string() })
}
}
impl fmt::Display for SearchOptions {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.sort_by)
}
}
Catch-All Query String
Capture the entire query string with ?:..name:
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/search?:..query")]
Search { query: String },
}
#[component]
fn Search(query: String) -> Element {
// Parse custom query format
rsx! { p { "Raw query: {query}" } }
}
URL /search?foo=bar&baz=qux → query = "foo=bar&baz=qux"
Reactive Query Parameters
Use ReadSignal to make parameters reactive:
#[component]
fn Search(q: ReadSignal<String>, page: ReadSignal<usize>) -> Element {
// Automatically recomputes when q or page changes
let results = use_memo(move || {
fetch_results(&q.read(), page())
});
rsx! {
input {
value: "{q}",
oninput: move |e| {
navigator().replace(Route::Search {
q: e.value(),
page: page(),
});
}
}
// Display results
}
}
See the query_segment_search example for a full implementation.
Hash Fragments
Capture URL hash fragments (anchor links) with #:name:
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/docs#:section")]
Docs { section: String },
}
#[component]
fn Docs(section: String) -> Element {
use_effect(move || {
// Scroll to section
if let Some(element) = document().get_element_by_id(§ion) {
element.scroll_into_view();
}
});
rsx! {
h1 { "Documentation" }
div { id: "introduction", "Introduction..." }
div { id: "installation", "Installation..." }
}
}
URL /docs#installation extracts section = "installation".
Hash Fragment State
Store application state in the hash:
#[derive(Clone, PartialEq, Default, Debug)]
struct AppState {
count: usize,
}
impl fmt::Display for AppState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "count:{}", self.count)
}
}
impl FromStr for AppState {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let count = s.strip_prefix("count:")
.and_then(|s| s.parse().ok())
.unwrap_or(0);
Ok(AppState { count })
}
}
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/app#:state")]
App { state: AppState },
}
Combining Parameters
Mix path, query, and hash parameters:
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/blog/:slug?:highlight#:section")]
BlogPost {
slug: String, // Path parameter
highlight: String, // Query parameter
section: String, // Hash fragment
},
}
URL /blog/my-post?highlight=code#comments extracts:
slug = "my-post"
highlight = "code"
section = "comments"
Navigating with Parameters
Using Link
rsx! {
Link {
to: Route::User { id: 123 },
"View User"
}
Link {
to: Route::Search {
q: "rust".to_string(),
page: Some(2),
},
"Search Results"
}
}
Using Navigator
let nav = use_navigator();
rsx! {
button {
onclick: move |_| {
nav.push(Route::BlogPost {
year: 2024,
month: 3,
slug: "new-post".to_string(),
});
},
"View Post"
}
}
URL Encoding
Parameters are automatically URL encoded/decoded:
#[route("/search?:q")]
Search { q: String },
"hello world" → /search?q=hello%20world
/search?q=hello%20world → q = "hello world"
Special characters are handled automatically:
Link {
to: Route::Search { q: "hello & goodbye".to_string() },
"Search"
}
// Generates: /search?q=hello%20%26%20goodbye
Type Safety Benefits
The enum router provides compile-time guarantees:
// ✅ Compiles - all parameters provided
Link { to: Route::User { id: 123 }, "User" }
// ❌ Compile error - missing parameter
Link { to: Route::User {}, "User" }
// ❌ Compile error - wrong type
Link { to: Route::User { id: "abc" }, "User" }
Compare with string-based routing:
// All compile, but some are wrong!
<a href="/user/123">User</a> // ✅ Correct
<a href="/user">User</a> // ❌ Missing ID - broken link
<a href="/user/abc">User</a> // ❌ Invalid ID - runtime error
Accessing Current Route
Get the current route with use_route():
#[component]
fn MyComponent() -> Element {
let route = use_route::<Route>();
match route {
Route::User { id } => rsx! { p { "Viewing user {id}" } },
Route::Home {} => rsx! { p { "On home page" } },
_ => rsx! { p { "Other page" } },
}
}
Best Practices
- Use specific types -
usize instead of String for IDs
- Validate in components - Don’t trust that parameters are valid
- Provide defaults - Use
Option or Default for optional params
- Keep URLs readable - Use descriptive parameter names
- Encode special characters - Let the router handle encoding
Common Patterns
#[route("/products?:page")]
Products { page: Option<usize> },
#[component]
fn Products(page: Option<usize>) -> Element {
let current_page = page.unwrap_or(1);
rsx! {
Link {
to: Route::Products { page: Some(current_page + 1) },
"Next Page"
}
}
}
Filtering
#[route("/products?:category&:min_price&:max_price")]
Products {
category: Option<String>,
min_price: Option<f64>,
max_price: Option<f64>,
},
Breadcrumbs
#[route("/docs/:..path")]
Docs { path: Vec<String> },
#[component]
fn Docs(path: Vec<String>) -> Element {
rsx! {
nav {
Link { to: Route::Docs { path: vec![] }, "Docs" }
for (i, segment) in path.iter().enumerate() {
" / "
Link {
to: Route::Docs {
path: path[..=i].to_vec()
},
"{segment}"
}
}
}
}
}