Protect unsaved changes
A user edits a form and attempts to navigate away before saving.
TanStack · Hook
useBlocker blocks TanStack Router navigation when a condition is met. It can expose the pending transition and controls for continuing or cancelling it.
useBlocker registers a navigation condition through shouldBlockFn. When blocking occurs, the hook exposes the pending navigation state and, with withResolver enabled, proceed and reset controls so the UI can decide whether to continue or cancel; enableBeforeUnload separately controls browser unload protection.
useBlocker(options)| Name | Type | Description |
|---|---|---|
shouldBlockFn | ShouldBlockFn | Required predicate or asynchronous predicate that receives transition details and determines whether navigation should be blocked. |
disabled | boolean | Disables the blocker entirely; defaults to false. |
enableBeforeUnload | boolean | (() => boolean) | Controls whether browser beforeUnload protection is enabled; defaults to true. |
withResolver | boolean | Controls whether the hook's resolver is used; defaults to false. |
An object containing status, transition details such as next, current, and action when blocked, plus proceed and reset controls.
import { useState } from 'react'
import { useBlocker } from '@tanstack/react-router'
export function Editor() {
const [dirty, setDirty] = useState(false)
const { status, proceed, reset } = useBlocker({
shouldBlockFn: () => dirty,
enableBeforeUnload: dirty,
withResolver: true,
})
return (
<>
<textarea onChange={() => setDirty(true)} />
{status === 'blocked' && (
<div>
<button onClick={proceed}>Leave</button>
<button onClick={reset}>Stay</button>
</div>
)}
</>
)
}Blocks leaving a dirty editor and lets the user continue or cancel the pending navigation.
A user edits a form and attempts to navigate away before saving.
An application must ask for confirmation before leaving a multi-step workflow.
A payment or other critical operation should not be interrupted by route changes.
useBlocker is a hook that blocks navigation when a condition is met. It requires an options object whose shouldBlockFn returns a boolean or Promise<boolean>.
Follow-up: How can the blocker inspect the transition? Pass a function accepting ShouldBlockFnArgs; it receives information about the current route, next route, and navigation action.
withResolver enables the resolver returned by the hook to control the decision. A blocked result exposes proceed to continue navigation and reset to cancel it and return to idle.
Follow-up: What state indicates a pending decision? Check status === 'blocked', then use the narrowed next, current, and action values to render context-aware UI.
enableBeforeUnload defaults to true and accepts either a boolean or a function returning a boolean. It controls whether the blocker registers protection for the browser beforeUnload event.
Follow-up: How would you avoid unload protection for a particular blocker? Set enableBeforeUnload to false while retaining shouldBlockFn for in-app navigation.
ShouldBlockFnShouldBlockFnArgsNavigation BlockingHistoryAction