Route Locking
Route locking temporarily blocks in-app navigation from the current route. While locked, navigation through a <Link> or router.navigate() is blocked.
Route locking only controls navigation handled by Retend’s router. It does not prevent browser-level actions such as closing the tab, entering a URL in the address bar, or refreshing the page. Use the browser’s beforeunload event for those actions.
Locking a Route
Call router.lock() to lock the current route:
import { useRouter } from 'retend/router'; export function EditPostForm() { const router = useRouter(); const handleInput = () => { // As soon as the user types something, lock them on the page router.lock(); }; return ( <form> <textarea onInput={handleInput} placeholder="Write your post..." /> </form> ); }
After router.lock() is called, in-app navigation away from the route is blocked.
Unlocking a Route
Call router.unlock() when the user has finished, such as after saving a form, to allow in-app navigation again:
import { useRouter } from 'retend/router'; import { Cell } from 'retend'; export function SettingsForm() { const router = useRouter(); const isDirty = Cell.source(false); const handleChange = () => { if (!isDirty.get()) { isDirty.set(true); router.lock(); } }; const handleSave = async () => { await saveSettings(); isDirty.set(false); // Allow navigation after the save completes router.unlock(); }; return ( <form> <input type="text" onInput={handleChange} /> <button type="button" onClick={handleSave}> Save </button> </form> ); }
Handling Blocked Navigation
When navigation is blocked, display a message explaining why, such as a warning about unsaved changes.
Retend dispatches a routelockprevented event on the router when it blocks a navigation attempt. Listen for this event to display a warning:
import { useRouter } from 'retend/router'; import { onSetup, Cell, If } from 'retend'; export function ProtectedForm() { const router = useRouter(); const showWarning = Cell.source(false); onSetup(() => { // This runs whenever a navigation is blocked const handleBlockedNavigation = (event: Event) => { showWarning.set(true); }; router.addEventListener('routelockprevented', handleBlockedNavigation); // Always clean up your listeners! return () => { router.removeEventListener('routelockprevented', handleBlockedNavigation); }; }); const handleDiscard = () => { router.unlock(); showWarning.set(false); // You could also manually navigate them away here if you wanted }; return ( <div> <textarea placeholder="Type something..."></textarea> {/* Show the warning dialog if navigation was blocked */} {If(showWarning, { true: () => ( <div class="confirmation-dialog"> <p>You have unsaved changes.</p> <button type="button" onClick={() => showWarning.set(false)}> Keep Editing </button> <button type="button" onClick={handleDiscard}> Discard & Leave </button> </div> ), })} </div> ); }
Use route locking to prevent users from leaving a route with unsaved work through in-app navigation.