When would a router render two matched branches into separate named outlets at once, and what does that cost?
answer
- several matches, one address
- regions that navigate independently
- each region needs its own empty state
- reconstruct every region from the URL
- transient panels are component state
basics
~20 sUse named outlets when two regions of a screen are independently routable and worth linking to — a list beside a detail, or a persistent side panel. The cost is that one URL must describe several branches at once.
solid answer
~40 sA level may declare more than one outlet, each with a name, and the route table assigns a branch to each name. One URL then resolves to several simultaneous matches, and a navigation can change one region while leaving the others matched — a list beside a detail, a persistent activity panel, or an overlay rendered above the screen it covers. Each outlet gets its own empty state, and its own failure and pending region, so one region going wrong does not blank the other. The cost is conceptual and practical: "what is on screen" is no longer a single path through the tree, every region must be reconstructible from the URL or a reload will produce a different screen than in-app navigation did, and the combinations you have to test multiply.
go deeper
Know that it exists: a level can hold more than one outlet, so one address can drive two regions of the screen at the same time. You will meet it before you need to design it.
Explain the mechanism: named outlets, one branch assigned per name, several matches rendered at once, and each region carrying its own empty, pending and failure states.
Show that you would design for cold loads and shared links first, and that you would reach for a parent-and-child chain when one region is naturally the ancestor of the other.
Weigh the long-term cost: addressable regions multiply the states the team must reason about and test, so reserve them for regions whose independence is part of the product.
## One URL, more than one matched branch The common case is a single outlet per level: one path, one chain, one screen. A router that supports **named outlets** relaxes that. A level declares several outlets, each identified by a name, and the table says which branch fills which name. Matching then produces not one chain but a set of them, all rendered at the same time inside the same level. That matters when two regions of a screen are genuinely independent and both deserve to be addressable: - a **list beside a detail**, where choosing an item changes only the detail region; - a **persistent secondary panel** — activity, help, a conversation — that stays while the main region navigates; - an **overlay above the screen it covers**, where the underlying region keeps its match instead of being replaced; - a **comparison layout** where two branches of the same shape are shown side by side. ## What the table and the URL have to supply The hard requirement is **reconstructibility**. If a region's branch cannot be derived from the address, then a link, a reload or a restored session shows something different from what in-app navigation produced. That desync is the defect this mechanism is most often blamed for, and it is a design mistake rather than a router bug. Practical options: 1. Both regions derive from the **same segments** — the detail region reads the identifier the main path already carries. 2. One region gets its **own part of the address**, so its state travels with the link. 3. A region is declared **deliberately transient**, with a defined default on a cold load. That is a legitimate choice as long as it is the documented behaviour and not an accident. ## What each outlet needs of its own - An **empty state**, for when its branch matches nothing. A region with no match must render something intentional, not a gap in the layout. - Its **own failure region**, so a failing panel does not take the main region with it. - Its **own pending region**, so one region waiting does not blank the whole screen. - A clear **ownership rule for shared data**, because two regions showing the same entity is exactly where people reach for hidden mutable state to keep them in step. ## What it costs | cost | why it appears | |---|---| | harder reasoning | the screen is a *set* of matches, so "what renders here" cannot be answered by reading one path | | link fidelity | every region must be reproducible from the address, or shared links and reloads diverge from in-app state | | history semantics | you must decide which region changes deserve their own step back, and say so consistently | | combinatorial testing | region states multiply instead of adding | | responsive layout | a multi-region shape has to collapse into one region on a narrow viewport, and something must decide which one wins | | focus and reading order | two live regions need a defined order and a defined place for focus to land after a region-only change | ## When it earns its keep, and when it does not It earns its keep when the regions are **independently meaningful**: each has content worth linking to, each has its own loading and failure story, and users move within one without disturbing the other. A mail client, an admin console with a persistent inspector, or a two-pane browse-and-read surface all fit. It does not earn its keep for ephemeral interface state. A confirmation dialog, a transient menu, a tooltip and a wizard step that nobody would ever link to are cheaper and clearer as component state. Routing them buys addressability you do not need and charges you the whole list above. The honest test is: **would you paste this region's state into a chat message?** If not, it is not routing's problem. ## A middle path Before reaching for named outlets, check whether one branch with a parameter does the job. A list-and-detail screen often works as a single chain where the list level renders both the list and its outlet, and the detail is an ordinary child. That gives you one path to reason about, retention of the list level for free, and a natural empty state through an index child. Named outlets are worth their cost when the regions are **not** in an ancestor relationship like that — when neither region is naturally the parent of the other, or when one must survive while the other is replaced wholesale.
- How do you handle a two-region screen on a narrow viewport?Decide which region is primary and show one at a time, driven by the same address so the choice is linkable. The regions keep their own matches; only the presentation collapses. What you must avoid is rendering both off-screen and letting focus land in a region the user cannot see.
- When is a panel better expressed as component state than as a second outlet?When nobody would link to it: a menu, a confirmation, a transient inspector, a step in a flow that must not be entered mid-way. Routing it adds addressability, history semantics and an extra empty state to maintain for a region whose whole life is one interaction.
saying these in an interview costs you the question
- Assumes a router can restore panel matches without the URL describing them
- Routes every dialog and menu as a second region
- Gives the regions one shared failure display for the whole screen
- Leaves a region with no match rendering an empty gap
- Keeps two regions in step through hidden shared mutable state
- Treats a list-and-detail pair as needing named outlets by default