Skip to main content

Overview

The Link component creates navigation links that integrate with the router. Unlike standard HTML anchors, Link enables client-side routing without full page reloads.

Basic Usage

use dioxus::prelude::*;

#[derive(Clone, Routable, PartialEq)]
enum Route {
    #[route("/")]
    Home {},
    #[route("/about")]
    About {},
}

#[component]
fn Home() -> Element {
    rsx! {
        Link { to: Route::About {}, "Go to About" }
    }
}

#[component]
fn About() -> Element {
    rsx! {
        Link { to: Route::Home {}, "Go to Home" }
    }
}

Props

to
NavigationTarget
required
The target route or URL. Can be a route enum variant or a string path.
// Internal route
Link { to: Route::Home {}, "Home" }

// String path
Link { to: "/about", "About" }

// External URL
Link { to: "https://dioxuslabs.com", "Dioxus Labs" }
children
Element
required
The content to render inside the link.
Link { to: Route::Home {},
    "Home"
}

// Or with complex content
Link { to: Route::About {},
    img { src: "/icon.png" }
    span { "About Us" }
}
active_class
Option<String>
CSS class applied when the link’s target matches the current route.
Link {
    to: Route::Home {},
    active_class: "active",
    "Home"
}
class
Option<String>
CSS class always applied to the link.
Link {
    to: Route::About {},
    class: "nav-link",
    "About"
}
new_tab
bool
default:"false"
Open the link in a new tab.
Link {
    to: "https://dioxuslabs.com",
    new_tab: true,
    "Dioxus Labs"
}
onclick
Option<EventHandler<MouseEvent>>
Custom click handler. By default, the handler runs after navigation.
Link {
    to: Route::Home {},
    onclick: move |evt| {
        println!("Link clicked!");
    },
    "Home"
}
onclick_only
bool
default:"false"
When true, only the custom onclick handler runs (navigation is disabled).
Link {
    to: Route::Home {},
    onclick_only: true,
    onclick: move |_| {
        println!("Custom action only");
        // Navigation does NOT occur
    },
    "Custom Action"
}
rel
Option<String>
The rel attribute for the generated anchor tag.For external links, defaults to "noopener noreferrer".
Link {
    to: "https://example.com",
    rel: "nofollow",
    "External Site"
}
onmounted
Option<EventHandler<MountedEvent>>
Handler called when the anchor element is mounted.
Link {
    to: Route::Home {},
    onmounted: move |evt| {
        println!("Link mounted");
    },
    "Home"
}
Links automatically receive an aria-current="page" attribute when their target matches the current route. You can style active links using the active_class prop:
rsx! {
    style { "
        .nav-link {{ color: gray; }}
        .nav-link.active {{ color: blue; font-weight: bold; }}
    " }
    
    nav {
        Link {
            to: Route::Home {},
            class: "nav-link",
            active_class: "active",
            "Home"
        }
        Link {
            to: Route::About {},
            class: "nav-link",
            active_class: "active",
            "About"
        }
    }
}

Internal Routes

Internal routes use client-side navigation:
Link { to: Route::Home {}, "Home" }
Link { to: "/about", "About" }

External URLs

External URLs are detected automatically and use standard browser navigation:
Link { to: "https://dioxuslabs.com", "Dioxus" }
Link { to: "mailto:[email protected]", "Email Us" }

HTML Output

The Link component renders as an HTML <a> tag:
Link {
    to: Route::About {},
    class: "btn",
    active_class: "active",
    id: "about-link",
    "About"
}
Generates:
<a href="/about" class="btn active" aria-current="page" id="about-link">
    About
</a>

Advanced Examples

Dynamic Routes

#[derive(Clone, Routable, PartialEq)]
enum Route {
    #[route("/user/:id")]
    UserProfile { id: usize },
}

#[component]
fn UserList() -> Element {
    let users = vec![1, 2, 3];
    
    rsx! {
        ul {
            for user_id in users {
                li {
                    Link {
                        to: Route::UserProfile { id: user_id },
                        "User {user_id}"
                    }
                }
            }
        }
    }
}
Link {
    to: Route::Settings {},
    class: "nav-link",
    active_class: "active",
    
    svg { class: "icon", /* ... */ }
    span { "Settings" }
}

Conditional Navigation

#[component]
fn Home() -> Element {
    let is_authenticated = use_signal(|| false);
    
    rsx! {
        Link {
            to: Route::Dashboard {},
            onclick: move |evt| {
                if !is_authenticated() {
                    evt.prevent_default();
                    // Show login modal instead
                }
            },
            "Dashboard"
        }
    }
}

Accessibility

  • Links automatically receive aria-current="page" when active
  • The underlying <a> tag is keyboard accessible
  • Screen readers announce links correctly
  • Modifier keys (Cmd/Ctrl + click) work as expected for opening in new tabs

Important Notes

Link must be used within a Router component. Using it outside a router context will panic in debug builds and render an inactive link in release builds.
For external URLs, the router lets the browser handle navigation. The new_tab prop has no effect on whether a link is considered active.

Source

View the source code: packages/router/src/components/link.rs

Build docs developers (and LLMs) love