useBeforeUnload
EditRequests the browser's standard leave-page confirmation when unsaved work should block navigation.
import { useEffect, useLayoutEffect, useRef } from "react";
export type BeforeUnloadPredicate = (this: void) => boolean;
const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
/** * Requests the browser's standard leave-page confirmation when enabled. */export const useBeforeUnload = ( shouldBlock: boolean | BeforeUnloadPredicate = true,): void => { const shouldBlockRef = useRef(shouldBlock); const shouldSubscribe = typeof shouldBlock === "function" || shouldBlock;
useIsomorphicLayoutEffect(() => { shouldBlockRef.current = shouldBlock; }, [shouldBlock]);
useIsomorphicLayoutEffect(() => { if (typeof window === "undefined" || !shouldSubscribe) return;
const handleBeforeUnload = (event: BeforeUnloadEvent) => { const block = typeof shouldBlockRef.current === "function" ? Reflect.apply(shouldBlockRef.current, undefined, []) : shouldBlockRef.current; if (!block) return;
event.preventDefault(); event.returnValue = ""; };
window.addEventListener("beforeunload", handleBeforeUnload);
return () => { window.removeEventListener("beforeunload", handleBeforeUnload); }; }, [shouldSubscribe]);};Download
Section titled “Download”wget -O src/hooks/useBeforeUnload.ts https://raw.githubusercontent.com/jrTilak/lazykit/HEAD/registry/react-hooks/useBeforeUnload.tstemp_dir="$(mktemp -d)" && bunx degit jrTilak/lazykit/registry/react-hooks "$temp_dir" && mv "$temp_dir/useBeforeUnload.ts" src/hooks/useBeforeUnload.ts && rm -r "$temp_dir"Examples
Section titled “Examples”import { useState } from "react";
import { useBeforeUnload } from "./useBeforeUnload";
export const UnsavedDraft = () => { const [draft, setDraft] = useState(""); const [savedDraft, setSavedDraft] = useState(""); useBeforeUnload(draft !== savedDraft);
return ( <section> <textarea value={draft} onChange={(event) => setDraft(event.currentTarget.value)} /> <button type="button" onClick={() => setSavedDraft(draft)}> Save </button> </section> );};shouldBlock(boolean | (() => boolean), default:true) — Boolean or latest predicate deciding whether to prevent thebeforeunloadevent.falseinstalls no listener; a predicate is evaluated for each event.
Returns
Section titled “Returns”void. The listener is removed on unmount and is never installed during server rendering. Browsers control the confirmation text; custom messages are intentionally unsupported.