Browse documentation
Documentation

Router: Page

Edit this guide on GitHub

Declares a page handler.

Use #[page] without a path string with module routing. The enclosing module determines the URL. A path starting with ./ extends the module path. An absolute path, such as #[page("/about")], chooses the URL independently of the module tree and requires separate registration.

A page serves GET by default. To serve other methods, name them in the attribute, using the same forms as #[route]: a single method (#[page(POST)]), a bracketed list ([GET, POST]), or * for every method.

Path strings follow the Path syntax.

module_router! registers module-derived handlers. For explicit paths, pass the function name to RouterBuilder::page or use discover.

Handler signature

The function must be async and return a Result containing a View. It may take cx: &Cx and one body parameter implementing FromRequest. Both are optional and may appear in either order. The body parameter may use a pattern such as Json(input): Json<T>.

Examples

Module-derived path (in src/app/about.rs under module_router!(), this serves /about):

#[page]
async fn about() -> Result<impl View> {
    Ok(view! { <h1>"About"</h1> })
}

Explicit path:

#[page("/users/{id}")]
async fn user_profile() -> Result<impl View> {
    Ok(view! { <h1>"User profile"</h1> })
}

Path below the module (in src/app/settings.rs under module_router!(), this serves /settings/export):

#[page("./export")]
async fn export() -> Result<impl View> {
    Ok(view! { <h1>"Export"</h1> })
}

Declaring a method (a form submission answered with a rendered view):

// src/app/signup.rs
#[page(POST)]
async fn signup(Form(input): Form<Signup>) -> Result<impl View> {
    Ok(view! { <h1>"Welcome, " (input.email)</h1> })
}

Reading a request body:

// src/app/contact.rs
#[page]
async fn contact(Form(input): Form<Search>) -> Result<impl View> {
    Ok(view! { <main>"searching for " (input.q)</main> })
}

Pages as components

A page doubles as a component: calling it inside view! renders it inline. A page that reads a request body takes the already-parsed value as a body prop instead of parsing the request.

// src/app/preview.rs
#[page]
async fn preview() -> Result<impl View> {
    let query = Search {
        q: String::from("hearth"),
    };
    Ok(view! {
        contact::contact(body: Form(query))
    })
}