Skip to content

Document #[end_layout] attribute and layout scoping behavior #627

@ThomasSteinbach

Description

@ThomasSteinbach

Problem

The router documentation does not explain the stateful scoping behavior of the #[layout()] attribute, nor does it mention the #[end_layout] attribute needed to close layout scopes.

This leads to a common bug where developers accidentally create nested/duplicate layouts when trying to apply the same layout to multiple routes.

Current Documentation Gap

The layouts documentation shows only single-route examples:

#[layout(Wrapper)]
    #[route("/")]
    Index {},

When developers want multiple routes to share the same layout, they naturally assume they need to add #[layout()] to each route:

// ❌ Creates NESTED layouts (2 Wrapper components rendered)
#[layout(Wrapper)]
#[route("/")]
Home {},

#[layout(Wrapper)]  // This NESTS inside the first layout!
#[route("/tokens")]
Tokens {},

This results in duplicate UI elements (e.g., 2 navigation bars, 2 headers) with no compile-time warning.

Root Cause

The #[layout()] attribute creates a persistent, stateful scope that remains active for all subsequent routes until explicitly closed with #[end_layout] (similar to how #[nest()] works with #[end_nest]).

What Should Be Documented

  1. Layout scoping is stateful - Once opened, it affects all subsequent routes
  2. The #[end_layout] attribute exists - Explicitly closes a layout scope
  3. Proper indentation convention - Visual hierarchy helps prevent mistakes
  4. Multiple routes under one layout - Show the correct pattern:
#[layout(Wrapper)]
    #[route("/")]
    Home {},
    
    #[route("/tokens")]
    Tokens {},
#[end_layout]
  1. Warning about duplicate layouts - Explain what happens if scopes aren't closed
  2. Debugging technique - Mention cargo expand to verify nesting levels

Real-World Impact

This bit us in production - our /tokens page rendered with 2 complete layouts (duplicate navigation, duplicate sidebars) while / rendered correctly. Debugging required:

  • Inspecting generated HTML with curl
  • Using cargo expand to examine macro-generated code
  • Reading Dioxus router source code

The fix was simple (#[end_layout]), but discovering it was not.

Comparison with Nested Routes

The nested routes documentation does explain this pattern for #[nest()]:

To finish a nest, we use the #[end_nest] attribute or the end of the enum.

Layouts should have equivalent documentation for #[end_layout].

Proposed Solution

Add a new section to the layouts documentation showing:

  • How to apply one layout to multiple routes
  • The #[end_layout] attribute
  • Warning about accidental nesting
  • Example of the wrong pattern vs correct pattern
  • Optional: debugging tips

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions