Which link activations must a client router hand back to the browser as a full document load?
answer
- interception is optional, always
- not ours to render
- the user aimed at a new tab
- a response the client cannot apply
- enhance a real anchor, never replace it
basics
~20 sA client router must decline anything it does not own or cannot apply: another origin or a path outside the app, a modified or middle click, a target or download attribute, and any response it cannot render.
solid answer
~50 sA client router intercepts clicks, but it must intercept only the ones it can honestly handle. It has to step aside for a target on another origin or outside the application's base path; for a click the user aimed elsewhere — middle button, or held modifier keys, which the browser turns into a new tab or window; for a link carrying a target or a download attribute; and for a target that is not an application route at all, such as a file or an API path. It must also fall back when the response is not something it can apply: a redirect off-origin, an authentication challenge, a response shape it does not understand, or a payload whose route code it can no longer load. The rule of thumb is to leave ordinary anchor semantics intact and treat interception as an optimisation that can always be declined.
go deeper
Know that a client router only handles links it owns: same app, plain left click, no new tab or download, and everything else is left to the browser.
List the interception conditions and explain why modifier and middle clicks must pass through, plus the responses that force a fallback document load.
Show that a hard load is a legitimate recovery path, not a defect, and that you design the failure so the user lands in a correct freshly bootstrapped page.
Decide the app-wide policy: what the router claims, what it cedes to whatever else is deployed on the origin, and how a forced document load is made cheap enough to be acceptable.
A client router works by intercepting activations that would otherwise be document loads and handling them in the running page. That interception is an **optimisation, not a takeover**: there are many activations it must not claim, and situations where it has claimed one and has to give it back. Getting this list right is what separates a router that feels native from one that breaks the browser. ## Activations the router must not intercept - **Another origin.** A link to a different scheme, host or port is not the application's to render. - **Outside the base path.** Apps often own only a sub-path; anything outside it belongs to whatever else is deployed there. - **Not a routable target.** A file, an asset, an API path, a mail or telephone scheme — nothing the route table can resolve. - **A different browsing context.** A link that asks to open in a new tab or window, or one that requests a download rather than a view. - **The user aimed elsewhere.** Middle-click, right-click, and clicks with a modifier key held are the browser's gestures for open-in-new-tab, open-in-new-window and save; swallowing them is one of the most common complaints about client-side routers. - **The event was already handled.** If something else called for the default to be prevented, the router should not re-handle it. A good check on all of these is that they are exactly the cases where the user would be surprised to stay on the current page. ## Responses the client cannot apply Even for a link the router rightly claimed, the answer may be one it cannot use: | Situation | Why the client cannot finish it | |---|---| | Redirect to another origin | the destination is outside the app's routing entirely | | Authentication or authorisation challenge | the flow may need a full document context and cookies set on it | | A response that is not a route payload | an error document or an unexpected content type has nothing to apply | | Route code that will not load | the chunk is gone or fails, so the segment cannot render | | A response that must set or clear credentials at the document level | applying it in place would leave the page in a mixed state | The correct recovery is the same in all of them: stop trying, and ask the browser to load the target URL as a document. The user pays one slow navigation and lands in a correct, freshly bootstrapped page. Silently failing or rendering half the new route is much worse. ## The deployment case, briefly There is one more forced hard load that deserves naming: the running client holds a build that no longer matches what the server serves, so the route code or payload shape it asks for is not there any more. The routing-level consequence is the same — fall back to a document load — while detecting and managing that mismatch is a deployment concern in its own right. ## Keep the anchor underneath All of this is much easier if the router enhances real anchors rather than replacing them: 1. Render a genuine link element with a real `href` to the target URL. 2. Attach the interception on activation, and check the conditions above before preventing the default. 3. If any condition fails, do nothing — the browser performs the navigation it was always going to perform. The payoff is that every fallback is free. Before the client code has loaded, during an error, with scripting unavailable, on a middle click — the link still works, because it was always a link. A router built on click handlers over non-link elements has to reimplement every one of those behaviours, and typically reimplements a subset. ## Where frameworks differ Most ship a link component that applies roughly this list, and most give you a way to force a document load for a specific link when you know the target is outside their control. What they differ on is how aggressively they claim same-origin links that do not match any route, and whether an unmatched path renders an in-app not-found view or falls through to the server. Neither answer is wrong, but you should know which one your app does, because it decides whether a typo in an internal link shows your styled not-found page or the host's plain one.
- Why should a client router build on a real anchor element rather than a click handler?Because the anchor already carries everything the router would otherwise have to reimplement: the status bar target, middle-click and modifier-key behaviour, the context menu, keyboard activation, and a working navigation before or without client code. The router then only has to decide when to prevent the default, and every case it declines falls back to correct browser behaviour for free.
- What should happen when a claimed navigation's response turns out to be a redirect to another origin?The client cannot render another origin, so it stops and asks the browser to load the target URL as a document, letting the redirect play out normally. The user pays one full load and lands in the right place. Trying to follow it in the running page either fails outright or produces a page whose URL and content disagree.
- If an in-app link points at a path no route matches, should the router intercept it?It depends on a deliberate choice. Claiming it lets the app render its own not-found view with the shell intact, which is usually the better experience; declining it lets the server answer, which is right when other things are deployed under the same origin. The important part is that the app picks one, because the two produce visibly different pages for the same mistake.
saying these in an interview costs you the question
- Intercepts middle-clicks and modifier-clicks, breaking open-in-new-tab.
- Claims cross-origin links and then cannot render them.
- Builds navigation on click handlers over non-link elements.
- Has no fallback when a navigation response cannot be applied.
- Treats a download or new-tab link as an ordinary in-app navigation.
- Thinks a full document load is always a bug rather than a valid recovery.