8000 `beforeunload` dialog triggered by redirect to external site even after original blocker proceed occurs · Issue #4094 · TanStack/router · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
beforeunload dialog triggered by redirect to external site even after original blocker proceed occurs #4094
Open
@dawsonbooth

Description

@dawsonbooth

Which project does this relate to?

Router

Describe the bug

There is a bug with the useBlocker hook where under specific conditions, both a custom UI blocker AND the browser's native beforeunload confirmation dialog appear in sequence. The custom UI blocker appears first, and then after calling proceed, the browser's native confirmation dialog also appears.

The issue occurs when all of the following conditions are met:

  1. withResolver is set to true (to enable the custom UI)
  2. Both enableBeforeUnload and shouldBlockFn return true until the hook is fully unmounted (in our case, based on form dirtiness detection)
  3. In the beforeLoad of the destination route, there is a throw redirect to an external site

Additionally, passing ignoreBlocker: true to the redirect function that is thrown does not prevent the browser confirmation dialog from showing.

Your Example Website or App

https://stackblitz.com/edit/vitejs-vite-hyxmxvkd?file=src%2Froutes%2Findex.tsx

Steps to Reproduce the Bug or Issue

  1. Create a component that uses useBlocker with:

    // In src/routes/index.tsx
    const { status, proceed, reset } = useBlocker({
      shouldBlockFn: () => true,
      enableBeforeUnload: () => true,
      withResolver: true,
    });
  2. Add a route with a beforeLoad function that contains a redirect to an external site:

    // In src/routes/external.tsx
    export const Route = createFileRoute('/external')({
      component: External,
      beforeLoad: () => {
        throw redirect({ href: 'https://example.com/' });
      },
    });
  3. Try to navigate to the '/external' route (you can add a link to it on the index page)

Expected behavior

When navigating to a route that redirects externally, only the custom UI blocker should appear. Once the user confirms by clicking "proceed" in the custom UI, the navigation should continue without triggering the browser's native beforeunload confirmation dialog.

Screenshots or Videos

No response

Platform

  • OS: macOS
  • Browser: Chrome
  • Version: 1.119.0

Additional context

I found a workaround by modifying the enableBeforeUnload function to include a check against the router state:

enableBeforeUnload: () => formIsDirty && router.state.status !== "pending"

This prevents the browser confirmation dialog from appearing when the router status is "pending", which occurs during the redirect. However, this seems like a workaround for what appears to be a bug in the interaction between useBlocker, beforeunload events, and redirects to external sites.

The key reproduction components are:

  1. A route using useBlocker with both shouldBlockFn and enableBeforeUnload returning true
  2. A separate route with a beforeLoad function that throws an external redirect
  3. When navigating to the external route, first the custom UI blocking appears, and after clicking "proceed", a browser confirmation dialog also appears

It would be helpful if there was a more official way to handle this case, perhaps by having ignoreBlocker: true properly bypass all forms of blocking, including the beforeunload event.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0