Skip to content

Async-friendly navigation blockers (custom confirmation UI) #218

Description

@uhyo

From a library audit (see AUDIT.md on branch claude/library-audit-sxpugz, §3.9).

Motivation

useBlocker's shouldBlock must answer synchronously during the navigate event, which in practice forces window.confirm(). Apps with design systems want a custom modal: block now, ask the user, then proceed or stay.

Proposal sketch

A blocked-state API in the spirit of React Router's useBlocker:

const blocker = useBlocker({ shouldBlock: () => isDirty });
// blocker.state: "unblocked" | "blocked"
// blocker.proceed(): re-run the blocked navigation
// blocker.reset(): stay

Implementation reality check: the Navigation API can't "pause" a navigation — once preventDefault() is called the navigation is dead. So proceed() must replay it (navigation.navigate/traverseTo with the recorded destination, state, info, history mode). Traversals can be replayed with navigation.traverseTo(key). That's exactly the fiddly logic users can't easily write themselves, which makes it worth having in the library. The captured NavigateEvent destination info in the blocker check (packages/router/src/core/NavigationAPIAdapter.ts) has everything needed.

Also worth documenting the limits (some traversals aren't cancelable — see #211, and form submissions would need formData replay or being declared unsupported).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions