-
Notifications
You must be signed in to change notification settings - Fork 200
Description
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
- Layout scoping is stateful - Once opened, it affects all subsequent routes
- The
#[end_layout]attribute exists - Explicitly closes a layout scope - Proper indentation convention - Visual hierarchy helps prevent mistakes
- Multiple routes under one layout - Show the correct pattern:
#[layout(Wrapper)]
#[route("/")]
Home {},
#[route("/tokens")]
Tokens {},
#[end_layout]- Warning about duplicate layouts - Explain what happens if scopes aren't closed
- Debugging technique - Mention
cargo expandto 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 expandto 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
- Tutorial code that works (but doesn't explain why): https://dioxuslabs.com/learn/0.7/tutorial/routing#adding-a-favorites-route
- Nested routes docs (good model to follow): https://dioxuslabs.com/learn/0.7/essentials/router/routes#nested-routes