Skip to content
LogoLogo

History & Navigation

Hooks for reading and reacting to browser navigation — from the low-level popstate event up to the newer Navigation API.

usePopState

Tracks location.pathname/history.state, updating on the popstate event — fired only by browser back/forward navigation (and history.back()/forward()/go()), never by the pushState/replaceState calls a client-side router makes itself. Falls back to { pathname: "/", state: null } during server rendering and before the client subscribes.

const { pathname } = usePopState();

useNavigationType

Classifies how the current page was reached — "navigate" (a fresh link/URL-bar navigation), "reload", "back_forward" (browser back/forward), or "prerender" — via the Navigation Timing API's performance.getEntriesByType("navigation")[0].type. This value is fixed once for the page's entire lifetime, unlike usePopState, which only ever fires for back/forward transitions after mount. Falls back to "navigate" during server rendering and where the Navigation Timing API is unsupported.

const navigationType = useNavigationType();
if (navigationType === "reload") restoreScrollPosition();

useNavigation

Wraps the Navigation API's window.navigationcurrentEntry, entries(), canGoBack/canGoForward — updating on its currententrychange event, which fires for both same-document and cross-document navigations the API observes (a superset of usePopState's popstate, which only ever fires for back/forward). Falls back to { canGoBack: false, canGoForward: false, currentEntry: null, entries: [] } during server rendering and permanently in browsers without the Navigation API. Chromium-only — no Safari/Firefox support yet.

const { canGoBack, currentEntry } = useNavigation();
if (canGoBack) window.navigation?.back();

useNavigationBlocker

Wraps the Navigation API's navigate event and event.intercept() to block/confirm in-app client-side route transitions — shouldBlock receives the destination URL and returns whether to hold the transition. While blocked is true, the navigation is intercepted and pending; call proceed() to let it complete, or reset() to clear the blocked state. Distinct from useBeforeUnload: that guards full page unload/tab close, this guards SPA route changes that never hit beforeunload. No-ops (never blocks) in browsers without the Navigation API. Chromium-only — no Safari/Firefox support yet.

const { blocked, proceed, reset } = useNavigationBlocker(() => isDirty);
if (blocked) return <ConfirmLeaveDialog onConfirm={proceed} onCancel={reset} />;

See Also