Skip to content

fix: skip blockers on non-cancelable navigate events#227

Merged
uhyo merged 1 commit into
masterfrom
claude/issue-211-mdhyul
Jul 12, 2026
Merged

fix: skip blockers on non-cancelable navigate events#227
uhyo merged 1 commit into
masterfrom
claude/issue-211-mdhyul

Conversation

@uhyo

@uhyo uhyo commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Fixes #211

Problem

When a blocker registered via useBlocker was active, the navigate handler called event.preventDefault() unconditionally. Per the Navigation API spec, some navigate events are not cancelable — notably certain back/forward traversals, depending on the browser and user activation. On those events preventDefault() is ignored, so shouldBlock() would run (possibly showing a confirm() dialog) while the navigation proceeded anyway — the user confirms "stay" and leaves regardless.

Changes

  • NavigationAPIAdapter.setupInterception: guard the blocker check with event.cancelable. When the event cannot be canceled, shouldBlock() is skipped entirely (no dialog whose answer can't be honored) and the navigation is handled normally (interception, loaders, etc.).
  • Test mock (__tests__/setup.ts): mock navigate events now carry a cancelable flag (default true), preventDefault() mimics real DOM behavior by being a no-op on non-cancelable events, and __simulateNavigationWithEvent accepts a cancelable option.
  • New test: a non-cancelable navigation with an active blocker verifies shouldBlock is never called, nothing is prevented, and the route is still intercepted.
  • Docs: the useBlocker JSDoc, docs/useBlocker-design.md, and the docs site (ApiHooksPage.tsx) now document that back/forward traversals may not be blockable in some browsers/situations, alongside the existing beforeunload caveat.

Verification

  • pnpm --filter @funstack/router test:run — 329 tests pass, no type errors
  • pnpm typecheck, pnpm lint, pnpm format:check — all clean

🤖 Generated with Claude Code

https://claude.ai/code/session_01JBczYkJZ5sdLWD4ue9zy37


Generated by Claude Code

Per the Navigation API spec, some navigate events are not cancelable
(notably certain back/forward traversals, depending on browser and user
activation). Calling preventDefault() on them is ignored, so blockers
would run shouldBlock() — possibly showing a confirm() dialog — while
the navigation proceeded regardless of the user's answer.

Check event.cancelable before running blockers so shouldBlock() is
skipped entirely when the navigation cannot be prevented, and document
the caveat in the useBlocker docs.

Fixes #211

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JBczYkJZ5sdLWD4ue9zy37
@uhyo
uhyo merged commit b18c0f3 into master Jul 12, 2026
1 check passed
@uhyo
uhyo deleted the claude/issue-211-mdhyul branch July 12, 2026 04:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useBlocker: preventDefault is called without checking event.cancelable

2 participants