---
title: 'Router'
description: "Yew's official router"
---

Routers in Single Page Applications (SPA) handle displaying different pages depending on what the URL is. Instead of the
default behavior of requesting a different remote resource when a link is clicked, the router instead sets the URL
locally to point to a valid route in your application. The router then detects this change and then decides what to
render.

Yew provides router support in the `yew-router` crate. To start using it, add the dependency to your `Cargo.toml`:

```sh
cargo add yew-router
```

The utilities needed are provided under `yew_router::prelude`,

## Usage

You start by defining a `Route`.

Routes are defined as an `enum` which derives `Routable`. This enum must be `Clone + PartialEq`.

```rust
use yew_router::prelude::*;

#[derive(Clone, Routable, PartialEq)]
enum Route {
    #[at("/")]
    Home,
    #[at("/secure")]
    Secure,
    #[not_found]
    #[at("/404")]
    NotFound,
}
```

A `Route` is paired with a `<Switch />` component, which finds the variant whose path matches the browser's
current URL and passes it to the `render` callback. The callback then decides what to render. In case no path is
matched, the router navigates to the path with `not_found` attribute. If no route is specified, nothing is rendered, and
a message is logged to the console stating that no route was matched.

Most of yew-router's components, in particular `<Link />` and `<Switch />`, must be (grand-)children of one of the Router components
(e.g. `<BrowserRouter />`). You usually only need a single Router in your app, most often rendered immediately by your most top-level `<App />`
component. The Router registers a context, which is needed for Links and Switches to function. An example is shown below.

:::caution
When using `yew-router` in a browser environment, `<BrowserRouter />` is highly recommended.
You can find other router flavors in the [API Reference](https://docs.rs/yew-router/).
:::

```rust
use yew_router::prelude::*;
use yew::prelude::*;

#[derive(Clone, Routable, PartialEq)]
enum Route {
    #[at("/")]
    Home,
    #[at("/secure")]
    Secure,
    #[not_found]
    #[at("/404")]
    NotFound,
}

#[component(Secure)]
fn secure() -> Html {
    let navigator = use_navigator().unwrap();

    let onclick = Callback::from(move |_| navigator.push(&Route::Home));
    html! {
        <div>
            <h1>{ "Secure" }</h1>
            <button {onclick}>{ "Go Home" }</button>
        </div>
    }
}

fn switch(routes: Route) -> Html {
    match routes {
        Route::Home => html! { <h1>{ "Home" }</h1> },
        Route::Secure => html! {
            <Secure />
        },
        Route::NotFound => html! { <h1>{ "404" }</h1> },
    }
}

#[component(Main)]
fn app() -> Html {
    html! {
        <BrowserRouter>
            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>
        </BrowserRouter>
    }
}
```

### Path Segments

It is also possible to extract information from a route using dynamic and named wildcard segments.
You can then access the post's id inside `<Switch />` and forward it to the appropriate component via properties.

```rust
use yew::prelude::*;
use yew_router::prelude::*;

#[derive(Clone, Routable, PartialEq)]
enum Route {
    #[at("/")]
    Home,
    #[at("/post/:id")]
    Post { id: String },
    #[at("/*path")]
    Misc { path: String },
}

fn switch(route: Route) -> Html {
    match route {
        Route::Home => html! { <h1>{ "Home" }</h1> },
        Route::Post { id } => html! {<p>{format!("You are looking at Post {}", id)}</p>},
        Route::Misc { path } => html! {<p>{format!("Matched some other path: {}", path)}</p>},
    }
}
```

:::note
You can have a normal `Post` variant instead of `Post {id: String}` too. For example, when `Post` is rendered
with another router, the field can then be redundant as the other router can match and handle the path. See the
[Nested Router](#nested-router) section below for details
:::

Note the fields must implement `Clone + PartialEq` as part of the `Route` enum. They must also implement
`std::fmt::Display` and `std::str::FromStr` for serialization and deserialization. Primitive types like integer, float,
and String already satisfy the requirements.

In case when the form of the path matches, but the deserialization fails (as per `FromStr`). The router will consider
the route as unmatched and try to render the not found route (or a blank page if the not found route is unspecified).

Consider this example:

```rust ,ignore
#[derive(Clone, Routable, PartialEq)]
enum Route {
    #[at("/news/:id")]
    News { id: u8 },
    #[not_found]
    #[at("/404")]
    NotFound,
}
// switch function renders News and id as is. Omitted here.
```

When the segment goes over 255, `u8::from_str()` fails with `ParseIntError`, the router will then consider the route
unmatched.

![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)

For more information about the route syntax and how to bind parameters, check
out [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params).

### Location

The router provides a universal `Location` struct via context which can be used to access routing information.
They can be retrieved by hooks or convenient functions on `ctx.link()`.

### Navigation

`yew_router` provides a handful of tools to work with navigation.

#### Link

A `<Link />` renders as an `<a>` element, the `onclick` event handler will call
[preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault), and push the targeted page to the
history and render the desired page, which is what should be expected from a Single Page App. The default `onclick` of a
normal anchor element would reload the page.

The `<Link />` component also passes its children to the `<a>` element. Consider it a replacement of `<a/>` for in-app
routes. Except you supply a `to` attribute instead of a `href`. An example usage:

```rust ,ignore
<Link<Route> to={Route::Home}>{ "click here to go home" }</Link<Route>>
```

Struct variants work as expected too:

```rust ,ignore
<Link<Route> to={Route::Post { id: "new-yew-release".to_string() }}>{ "Yew!" }</Link<Route>>
```

#### Navigator API

Navigator API is provided for both function components and struct components. They enable callbacks to change the
route. A `Navigator` instance can be obtained in either case to manipulate the route.

##### Function Components

For function components, the `use_navigator` hook re-renders the component when the underlying navigator provider changes.
Here is how to implement a button that navigates to the `Home` route when clicked.

```rust ,ignore
#[component]
pub fn MyComponent() -> Html {
    let navigator = use_navigator().unwrap();
    let onclick = Callback::from(move |_| navigator.push(&Route::Home));

    html! {
        <button {onclick}>{"Click to go home"}</button>
    }
}
```

If you want to replace the current location instead of pushing a new location onto the stack, use `navigator.replace()`
instead of `navigator.push()`.

You may notice `navigator` has to move into the callback, so it cannot be used again for other callbacks. Luckily `navigator`
implements `Clone`, here is for example how to have multiple buttons for different routes:

```rust ,ignore
use yew::prelude::*;
use yew_router::prelude::*;

#[component(NavItems)]
pub fn nav_items() -> Html {
    let navigator = use_navigator().unwrap();

    let go_home_button = {
        let navigator = navigator.clone();
        let onclick = Callback::from(move |_| navigator.push(&Route::Home));
        html! {
            <button {onclick}>{"click to go home"}</button>
        }
    };

    let go_to_first_post_button = {
        let navigator = navigator.clone();
        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: "first-post".to_string() }));
        html! {
            <button {onclick}>{"click to go the first post"}</button>
        }
    };

    let go_to_secure_button = {
        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));
        html! {
            <button {onclick}>{"click to go to secure"}</button>
        }
    };

    html! {
        <>
            {go_home_button}
            {go_to_first_post_button}
            {go_to_secure_button}
        </>
    }
}
```

##### Struct Components

For struct components, the `Navigator` instance can be obtained through the `ctx.link().navigator()` API. The rest is
identical to the function component case. Here is an example of a view function that renders a single button.

```rust ,ignore
fn view(&self, ctx: &Context<Self>) -> Html {
    let navigator = ctx.link().navigator().unwrap();
    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));
    html!{
        <button {onclick}>{"Go Home"}</button>
    }
}
```

#### Redirect

`yew-router` also provides a `<Redirect />` component in the prelude. It can be used to achieve similar effects as the
navigator API. The component accepts a
`to` attribute as the target route. When a `<Redirect/>` is rendered users will be redirected to the route specified in props.
Here is an example:

```rust ,ignore
#[component(SomePage)]
fn some_page() -> Html {
    // made-up hook `use_user`
    let user = match use_user() {
        Some(user) => user,
        // Redirects to the login page when user is `None`.
        None => return html! {
            <Redirect<Route> to={Route::Login}/>
        },
    };
    // ... actual page content.
}
```

:::tip `Redirect` vs `Navigator`, which to use
The Navigator API is the only way to manipulate route in callbacks.
While `<Redirect />` can be used as return values in a component. You might also want to use `<Redirect />` in another
non-component context, for example in the switch function of a [Nested Router](#nested-router).
:::

### Listening to Changes

#### Function Components

You can use `use_location` and `use_route` hooks. Your components will re-render when
provided values change.

#### Struct Components

In order to react on route changes, you can pass a callback closure to the `add_location_listener()` method of `ctx.link()`.

:::note
The location listener will get unregistered once it is dropped. Make sure to store the handle inside your
component state.
:::

```rust ,ignore
fn create(ctx: &Context<Self>) -> Self {
    let listener = ctx.link()
        .add_location_listener(ctx.link().callback(
            // handle event
        ))
        .unwrap();
    MyComponent {
        _listener: listener
    }
}
```

`ctx.link().location()` and `ctx.link().route::<R>()` can also be used to retrieve the location and the route once.

### Query Parameters

#### Specifying query parameters when navigating

In order to specify query parameters when navigating to a new route, use either `navigator.push_with_query` or
the `navigator.replace_with_query` functions. It uses the `ToQuery` trait to serialize the parameters into a query string for the URL. The `ToQuery` trait is automatically implemented for `serde` so any type that implements `Serialize` can be passed. In its simplest form, this is just a `HashMap` containing string pairs. In more complex scenarios the `ToQuery` trait can be implemented manually for a custom query format.

#### Obtaining query parameters for the current route

`location.query` is used to obtain the query parameters. It uses the `FromQuery` trait to deserialize the parameters from the query string
in the URL. The `FromQuery` trait is automatically implemented for `serde` so any type that implements `Deserialize` can be passed. If the URL is formatted in an custom way, a manual implementation of `FromQuery` can be used.

## Nested Router

Nested router can be useful when the app grows larger. Consider the following router structure:

<!--
The graph is produced with the following code, with graphviz.
To reproduce. Save the code in a file, say `input.dot`,
And run `$ dot -Tsvg input.dot  -o nested-router.svg`

digraph {
    bgcolor=transparent
    node [shape=box style="filled, rounded" fillcolor=white]
    Home; News; Contact; "Not Found"; Profile; Friends; Theme; SettingsNotFound [label="Not Found"];

    node [fillcolor=lightblue style="filled, rounded"]
    "Main Router"; "Settings Router";

    "Main Router" -> {Home News Contact "Not Found" "Settings Router"} [arrowhead=none]
    "Settings Router" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]
    SettingsNotFound -> "Not Found" [constraint=false]
}
-->

<!--
Also the dark-themed version:
digraph {
    bgcolor=transparent
    node [shape=box style="filled, rounded" fillcolor=grey color=white fontcolor=white]
    Home; News; Contact; "Not Found"; Profile; Friends; Theme; SettingsNotFound [label="Not Found"];

    node [fillcolor=lightblue style="filled, rounded" color=white fontcolor=black]
    "Main Router"; "Settings Router";

    "Main Router" -> {Home News Contact "Not Found" "Settings Router"} [arrowhead=none color=white]
    "Settings Router" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]
    SettingsNotFound -> "Not Found" [constraint=false color=white]
}
-->

import useBaseUrl from '@docusaurus/useBaseUrl'
import ThemedImage from '@theme/ThemedImage'

<ThemedImage
    alt="nested router structure"
    sources={{
        light: useBaseUrl('/img/nested-router-light.svg'),
        dark: useBaseUrl('/img/nested-router-dark.svg'),
    }}
/>

The nested `SettingsRouter` handles all URLs that start with `/settings`. Additionally, it redirects URLs that are not
matched to the main `NotFound` route. So `/settings/gibberish` will redirect to `/404`.

It can be implemented with the following code:

```rust
use yew::prelude::*;
use yew_router::prelude::*;
use gloo::utils::window;
use wasm_bindgen::UnwrapThrowExt;

#[derive(Clone, Routable, PartialEq)]
enum MainRoute {
    #[at("/")]
    Home,
    #[at("/news")]
    News,
    #[at("/contact")]
    Contact,
    #[at("/settings")]
    SettingsRoot,
    #[at("/settings/*")]
    Settings,
    #[not_found]
    #[at("/404")]
    NotFound,
}

#[derive(Clone, Routable, PartialEq)]
enum SettingsRoute {
    #[at("/settings")]
    Profile,
    #[at("/settings/friends")]
    Friends,
    #[at("/settings/theme")]
    Theme,
    #[not_found]
    #[at("/settings/404")]
    NotFound,
}

fn switch_main(route: MainRoute) -> Html {
    match route {
        MainRoute::Home => html! {<h1>{"Home"}</h1>},
        MainRoute::News => html! {<h1>{"News"}</h1>},
        MainRoute::Contact => html! {<h1>{"Contact"}</h1>},
        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },
        MainRoute::NotFound => html! {<h1>{"Not Found"}</h1>},
    }
}

fn switch_settings(route: SettingsRoute) -> Html {
    match route {
        SettingsRoute::Profile => html! {<h1>{"Profile"}</h1>},
        SettingsRoute::Friends => html! {<h1>{"Friends"}</h1>},
        SettingsRoute::Theme => html! {<h1>{"Theme"}</h1>},
        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}
    }
}

#[component(App)]
pub fn app() -> Html {
    html! {
        <BrowserRouter>
            <Switch<MainRoute> render={switch_main} />
        </BrowserRouter>
    }
}
```

:::caution

If you want more ergonomic nested router support. Please comment under [the first-class nested routing RFC](https://github.com/yewstack/yew/discussions/4111).

:::

### Basename

It's possible to define a basename with `yew-router`.
A basename is a common prefix of all routes. Both the Navigator API and
`<Switch />` component respect basename setting. All pushed routes will be
prefixed with the basename and all switches will strip the basename before
trying to parse the path into a `Routable`.

If a basename prop is not supplied to the Router component, it will use
the href attribute of the `<base />` element in your HTML file and
fallback to `/` if no `<base />` is present in the HTML file.

## Relevant examples

- [Router](https://github.com/yewstack/yew/tree/master/examples/router)

## API Reference

- [yew-router](https://docs.rs/yew-router/)
