Layouts

Layouts allow you to wrap all child routes in a component. This can be useful when creating something like a header that will be used in many different routes.

[Outlet] tells the router where to render content in layouts. In the following example,the Index will be rendered within the [Outlet].

This page is built with the Dioxus. It uses Layouts in several different places. Here is an outline of how layouts are used on the current page. Hover over different layouts to see what elements they are on the page.

#[derive(Clone, Routable, PartialEq, Eq, Serialize, Deserialize)]
#[rustfmt::skip]
pub enum Route {
	#[layout(HeaderFooter)]
		// ... other routes
		#[layout(DocsSidebars)]
			#[route("/learn")]
			Docs {},
}

Here is a more complete example of a layout wrapping the body of a page.

#[derive(Routable, Clone)]
#[rustfmt::skip]
enum Route {
    #[layout(Wrapper)]
        #[route("/")]
        Index {},
}

#[component]
fn Wrapper(cx: Scope) -> Element {
    render! {
        header { "header" }
        // The index route will be rendered here
        Outlet::<Route> { }
        footer { "footer" }
    }
}

#[component]
fn Index(cx: Scope) -> Element {
    render! {
        h1 { "Index" }
    }
}

The example above will output the following HTML (line breaks added forreadability):

<header>header</header>
<h1>Index</h1>
<footer>footer</footer>

Layouts with dynamic segments

You can combine layouts with nested routes to create dynamic layouts with content that changes based on the current route.

Just like routes, layouts components must accept a prop for each dynamic segment in the route. For example, if you have a route with a dynamic segment like /:name, your layout component must accept a name prop:

#[derive(Routable, Clone)]
#[rustfmt::skip]
enum Route {
    #[nest("/:name")]
        #[layout(Wrapper)]
            #[route("/")]
            Index {
                name: String,
            },
}

#[component]
fn Wrapper(cx: Scope, name: String) -> Element {
    render! {
        header { "Welcome {name}!" }
        // The index route will be rendered here
        Outlet::<Route> { }
        footer { "footer" }
    }
}

#[component]
fn Index(cx: Scope, name: String) -> Element {
    render! {
        h1 { "This is a homepage for {name}" }
    }
}

Or to get the full route, you can use the use_route hook.

#[derive(Routable, Clone)]
#[rustfmt::skip]
enum Route {
    #[layout(Wrapper)]
        #[route("/:name")]
        Index {
            name: String,
        },
}

#[component]
fn Wrapper(cx: Scope) -> Element {
    let full_route = use_route::<Route>(cx).unwrap();
    render! {
        header { "Welcome to {full_route}!" }
        // The index route will be rendered here
        Outlet::<Route> { }
        footer { "footer" }
    }
}

#[component]
fn Index(cx: Scope, name: String) -> Element {
    render! {
        h1 { "This is a homepage for {name}" }
    }
}