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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions