Skip to content

Instantly share code, notes, and snippets.

@scvnc
Created March 20, 2026 20:29
Show Gist options
  • Select an option

  • Save scvnc/6a2a94053a8bbfb5a6063f100f3befbf to your computer and use it in GitHub Desktop.

Select an option

Save scvnc/6a2a94053a8bbfb5a6063f100f3befbf to your computer and use it in GitHub Desktop.
A pattern to DRY up your 'You have unsaved changes, are you sure you'd like to navigate away' checks.
// This is a gist to describe the concept and not a full working example.
// Use this hook to signal to the app that you would like to block navigation when your form is dirty
useNavigationGuard(form.isDirty, {
message: "Your work hasn't been saved. Are you sure you want to continue?",
cancel: 'Go Back',
proceed: 'Continue without saving'
})
// Rough implementation below
interface NavigationGuardOptions {
message: string;
cancelLabel: string;
proceedLabel: string;
}
const useNavigationGuard = (isBlocked: MaybeRef<boolean>, options) => {
// Navigation Guard is
const guard: NavigationGuard = (from, to) => {
if(!isBlocked.value) {
// This guard is not blocking, continue navigation
return true;
}
// Otherwise, lets ask the user (async!)
// ..and showConfirm should likely be injected so that the app can decide how to show the confirmation dialog
// Do you want it to be a browser dialog or some other dom element system?
const result = await showConfirm(options);
return result;
})
// NavigationManager is a special singleton service that manages a list of form guards that must be consulted before
// allowing navigation.
// This should get hooked in to the SPA router's guard system, but there is also an opportunity to
// hook into any large tab navigation systems you have.
onComponentMounted(() => {
NavigationManager.addGuard(guard)
})
onComponentWillUnmount(() => {
NavigationManager.removeGuard(guard)
})
// and also handle the window.unload case
useWindowUnload(...);
}
const useWindowUnload = (isBlocked: MaybeRef<boolean>, message: string) => {
useEventListener(window, 'beforeunload', (e) => {
// https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event#examples
const _isBlocked = unref(isBlocked);
if (_isBlocked) {
e.preventDefault();
e.returnValue = message;
return e.returnValue;
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment