Exit Prompt
Holds a navigation while there is unsaved work, and asks before letting it go. A navigation inside the application gets this component's own dialog; closing the tab or reloading arms the browser's own prompt.
Two departures, two mechanisms
NavigationManager.RegisterLocationChangingHandler,
which never leaves C#, so the wording and the buttons match the rest of your interface.
Closing the tab, reloading, or following a link out of the application arms the browser's beforeunload prompt.
Browsers deliberately ignore a custom message there and show their own wording; that cannot be changed from script,
which is exactly why the in-application case is handled separately.
It cannot be rendered on the server
OnInitialized registers a navigation lock, which the server-side navigation manager used for
prerendering and static server rendering does not support. Rendering the component there throws
NotSupportedException. Put it inside an interactive render mode, or hold it back until the
surrounding component is interactive.
Guarding a Form
Custom Wording
Title, Message, StayLabel and LeaveLabel all fall back to
localized defaults. Message is not used for the browser's own prompt, which shows its own wording.
Stay renders as ButtonVariant.Outline and Leave as ButtonVariant.Destructive.
Behaviour
Bind Enabled to your own field. The component writes to its own Enabled
parameter when the visitor chooses to leave. If you pass a constant or an expression that does not change,
the next render restores the old value and re-arms the guard.
The navigation is refused, not held open. The handler calls PreventNavigation(),
remembers the target and returns immediately. Holding the router open until a button is pressed moved the URL without
rendering the new page, because the reissued navigation was re-entrant within the pipeline still processing the refused one.
Refusing first and navigating from the button's own handler keeps the two apart.
Leave clears the guard before reissuing. On Leave the component sets Enabled to false,
disarms the browser prompt, raises OnLeft, and only then navigates.
Dismissing the dialog counts as staying. Closing it any way other than the Leave button runs the same
path as the Stay button and raises OnStayed. While a navigation is already held, a second one is not intercepted.
Several prompts on a page. Each guards its own work, and the first enabled one prompts. Place one near the form it guards.
It cannot be rendered on the server. OnInitialized calls
NavigationManager.RegisterLocationChangingHandler, and the server-side navigation manager used for
prerendering and static server rendering does not support a navigation lock. Rendering the component there throws
NotSupportedException: To support navigation locks, HttpNavigationManager must override SetNavigationLockState.
Place it inside an interactive render mode, or hold it back until the component is interactive. The demo above does
the second: it renders only once this page is interactive.
The browser prompt fails quietly. Its JavaScript module is loaded inside a try/catch. If that load fails, in-application navigation is still guarded, because that path never leaves C#. Only the browser-level prompt is lost.