<html lang="en">
<head></head>
<body>

<form id="mainForm" method="post" action="https://stackblitz.com/run" target="_self">
<input type="hidden" name="project[files][.gitignore]" value="node_modules
.DS_Store
dist
dist-ssr
*.local
">
<input type="hidden" name="project[files][README.md]" value="# TanStack Router - Navigation Blocking Example

An example demonstrating navigation blocking and confirmation.

- [TanStack Router Docs](https://tanstack.com/router)

## Start a new project based on this example

To start a new project based on this example, run:

```sh
npx gitpick TanStack/router/tree/main/examples/react/navigation-blocking navigation-blocking
```

## Getting Started

Install dependencies:

```sh
pnpm install
```

Start the development server:

```sh
pnpm dev
```

## Build

Build for production:

```sh
pnpm build
```

## About This Example

This example demonstrates:

- Navigation blocking
- Unsaved changes detection
- Navigation confirmation dialogs
- Form protection
- User experience patterns
">
<input type="hidden" name="project[files][index.html]" value="&lt;!doctype html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vite App&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;&lt;/div&gt;
    &lt;script type=&quot;module&quot; src=&quot;/src/main.tsx&quot;&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
">
<input type="hidden" name="project[files][package.json]" value="{&quot;name&quot;:&quot;tanstack-router-react-example-navigation-blocking&quot;,&quot;private&quot;:true,&quot;type&quot;:&quot;module&quot;,&quot;scripts&quot;:{&quot;dev&quot;:&quot;vite --port 3000&quot;,&quot;build&quot;:&quot;vite build &amp;&amp; tsc --noEmit&quot;,&quot;preview&quot;:&quot;vite preview&quot;,&quot;start&quot;:&quot;vite&quot;},&quot;dependencies&quot;:{&quot;@tailwindcss/vite&quot;:&quot;^4.1.18&quot;,&quot;@tanstack/react-query&quot;:&quot;^5.90.0&quot;,&quot;@tanstack/react-router&quot;:&quot;https://pkg.pr.new/TanStack/router/@tanstack/react-router@a8b8021139e1f21e979e462e14ed8c15d4ce0f92&quot;,&quot;@tanstack/react-router-devtools&quot;:&quot;https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@a8b8021139e1f21e979e462e14ed8c15d4ce0f92&quot;,&quot;react&quot;:&quot;^19.0.0&quot;,&quot;react-dom&quot;:&quot;^19.0.0&quot;,&quot;redaxios&quot;:&quot;^0.5.1&quot;,&quot;tailwindcss&quot;:&quot;^4.1.18&quot;},&quot;devDependencies&quot;:{&quot;@types/react&quot;:&quot;^19.0.8&quot;,&quot;@types/react-dom&quot;:&quot;^19.0.3&quot;,&quot;@vitejs/plugin-react&quot;:&quot;^4.3.4&quot;,&quot;typescript&quot;:&quot;^5.7.2&quot;,&quot;vite&quot;:&quot;^7.1.7&quot;}}">
<input type="hidden" name="project[files][tsconfig.json]" value="{
  &quot;compilerOptions&quot;: {
    &quot;strict&quot;: true,
    &quot;esModuleInterop&quot;: true,
    &quot;jsx&quot;: &quot;react-jsx&quot;,
    &quot;lib&quot;: [&quot;DOM&quot;, &quot;DOM.Iterable&quot;, &quot;ES2022&quot;],
    &quot;skipLibCheck&quot;: true
  }
}
">
<input type="hidden" name="project[files][vite.config.js]" value="import { defineConfig } from &#39;vite&#39;
import react from &#39;@vitejs/plugin-react&#39;
import tailwindcss from &#39;@tailwindcss/vite&#39;

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [tailwindcss(), react()],
})
">
<input type="hidden" name="project[files][.vscode/settings.json]" value="{
  &quot;files.watcherExclude&quot;: {
    &quot;**/routeTree.gen.ts&quot;: true
  },
  &quot;search.exclude&quot;: {
    &quot;**/routeTree.gen.ts&quot;: true
  },
  &quot;files.readonlyInclude&quot;: {
    &quot;**/routeTree.gen.ts&quot;: true
  }
}
">
<input type="hidden" name="project[files][src/main.tsx]" value="import {
  Link,
  Outlet,
  RouterProvider,
  createRootRoute,
  createRoute,
  createRouter,
  useBlocker,
} from &#39;@tanstack/react-router&#39;
import { TanStackRouterDevtools } from &#39;@tanstack/react-router-devtools&#39;
import React from &#39;react&#39;
import ReactDOM from &#39;react-dom/client&#39;
import &#39;./styles.css&#39;

const rootRoute = createRootRoute({
  component: RootComponent,
})

function RootComponent() {
  // block going from editor-1 to /foo/123?hello=world
  const { proceed, reset, status } = useBlocker({
    shouldBlockFn: ({ current, next }) =&gt; {
      if (
        current.routeId === &#39;/editor-1&#39; &amp;&amp;
        next.fullPath === &#39;/foo/$id&#39; &amp;&amp;
        next.params.id === &#39;123&#39; &amp;&amp;
        next.search.hello === &#39;world&#39;
      ) {
        return true
      }
      return false
    },
    enableBeforeUnload: false,
    withResolver: true,
  })

  return (
    &lt;&gt;
      &lt;div className=&quot;p-2 flex gap-2 text-lg&quot;&gt;
        &lt;Link
          to=&quot;/&quot;
          activeProps={{
            className: &#39;font-bold&#39;,
          }}
          activeOptions={{ exact: true }}
        &gt;
          Home
        &lt;/Link&gt;{&#39; &#39;}
        &lt;Link
          to=&quot;/editor-1&quot;
          activeProps={{
            className: &#39;font-bold&#39;,
          }}
        &gt;
          Editor 1
        &lt;/Link&gt;{&#39; &#39;}
        &lt;Link
          to={&#39;/editor-1/editor-2&#39;}
          activeProps={{
            className: &#39;font-bold&#39;,
          }}
        &gt;
          Editor 2
        &lt;/Link&gt;{&#39; &#39;}
        &lt;Link
          to=&quot;/foo/$id&quot;
          params={{ id: &#39;123&#39; }}
          search={{ hello: &#39;world&#39; }}
          activeProps={{
            className: &#39;font-bold&#39;,
          }}
          activeOptions={{ exact: true, includeSearch: true }}
        &gt;
          foo 123
        &lt;/Link&gt;{&#39; &#39;}
        &lt;Link
          to=&quot;/foo/$id&quot;
          params={{ id: &#39;456&#39; }}
          search={{ hello: &#39;universe&#39; }}
          activeProps={{
            className: &#39;font-bold&#39;,
          }}
          activeOptions={{ exact: true, includeSearch: true }}
        &gt;
          foo 456
        &lt;/Link&gt;{&#39; &#39;}
      &lt;/div&gt;
      &lt;hr /&gt;

      {status === &#39;blocked&#39; &amp;&amp; (
        &lt;div className=&quot;mt-2&quot;&gt;
          &lt;div&gt;
            Are you sure you want to leave editor 1 for /foo/123?hello=world ?
          &lt;/div&gt;
          &lt;button
            className=&quot;bg-lime-500 text-white rounded-sm p-1 px-2 mr-2&quot;
            onClick={proceed}
          &gt;
            YES
          &lt;/button&gt;
          &lt;button
            className=&quot;bg-red-500 text-white rounded-sm p-1 px-2&quot;
            onClick={reset}
          &gt;
            NO
          &lt;/button&gt;
        &lt;/div&gt;
      )}
      &lt;Outlet /&gt;
      &lt;TanStackRouterDevtools position=&quot;bottom-right&quot; /&gt;
    &lt;/&gt;
  )
}

const indexRoute = createRoute({
  getParentRoute: () =&gt; rootRoute,
  path: &#39;/&#39;,
  component: IndexComponent,
})

function IndexComponent() {
  return (
    &lt;div className=&quot;p-2&quot;&gt;
      &lt;h3&gt;Welcome Home!&lt;/h3&gt;
    &lt;/div&gt;
  )
}

const fooRoute = createRoute({
  getParentRoute: () =&gt; rootRoute,
  path: &#39;foo/$id&#39;,
  validateSearch: (search) =&gt; ({ hello: search.hello }) as { hello: string },
  component: () =&gt; &lt;&gt;foo {fooRoute.useParams().id}&lt;/&gt;,
})

const editor1Route = createRoute({
  getParentRoute: () =&gt; rootRoute,
  path: &#39;editor-1&#39;,
  component: Editor1Component,
})

function Editor1Component() {
  const [value, setValue] = React.useState(&#39;&#39;)

  // Block leaving editor-1 if there is text in the input
  const { proceed, reset, next, current, status } = useBlocker({
    shouldBlockFn: () =&gt; value !== &#39;&#39;,
    enableBeforeUnload: () =&gt; value !== &#39;&#39;,
    withResolver: true,
  })

  return (
    &lt;div className=&quot;flex flex-col p-2&quot;&gt;
      &lt;h3&gt;Editor 1&lt;/h3&gt;
      &lt;div&gt;
        &lt;input
          value={value}
          onChange={(e) =&gt; setValue(e.target.value)}
          className=&quot;border&quot;
        /&gt;
      &lt;/div&gt;
      &lt;hr className=&quot;m-2&quot; /&gt;
      &lt;Link to=&quot;/editor-1/editor-2&quot;&gt;Go to Editor 2&lt;/Link&gt;
      &lt;Outlet /&gt;

      {status === &#39;blocked&#39; &amp;&amp; (
        &lt;div className=&quot;mt-2&quot;&gt;
          &lt;div&gt;Are you sure you want to leave editor 1?&lt;/div&gt;
          &lt;div&gt;
            You are going from {current.pathname} to {next.pathname}
          &lt;/div&gt;
          &lt;button
            className=&quot;bg-lime-500 text-white rounded-sm p-1 px-2 mr-2&quot;
            onClick={proceed}
          &gt;
            YES
          &lt;/button&gt;
          &lt;button
            className=&quot;bg-red-500 text-white rounded-sm p-1 px-2&quot;
            onClick={reset}
          &gt;
            NO
          &lt;/button&gt;
        &lt;/div&gt;
      )}
    &lt;/div&gt;
  )
}

const editor2Route = createRoute({
  getParentRoute: () =&gt; editor1Route,
  path: &#39;editor-2&#39;,
  component: Editor2Component,
})

function Editor2Component() {
  const [value, setValue] = React.useState(&#39;&#39;)

  return (
    &lt;div className=&quot;p-2&quot;&gt;
      &lt;h3&gt;Editor 2&lt;/h3&gt;
      &lt;input
        value={value}
        onChange={(e) =&gt; setValue(e.target.value)}
        className=&quot;border&quot;
      /&gt;
    &lt;/div&gt;
  )
}

const routeTree = rootRoute.addChildren([
  indexRoute,
  fooRoute,
  editor1Route.addChildren([editor2Route]),
])

// Set up a Router instance
const router = createRouter({
  routeTree,
  defaultPreload: &#39;intent&#39;,
  scrollRestoration: true,
})

const rootElement = document.getElementById(&#39;app&#39;)!

if (!rootElement.innerHTML) {
  const root = ReactDOM.createRoot(rootElement)

  root.render(&lt;RouterProvider router={router} /&gt;)
}
">
<input type="hidden" name="project[files][src/styles.css]" value="@import &#39;tailwindcss&#39;;

@layer base {
  *,
  ::after,
  ::before,
  ::backdrop,
  ::file-selector-button {
    border-color: var(--color-gray-200, currentcolor);
  }
}

html {
  color-scheme: light dark;
}
* {
  @apply border-gray-200 dark:border-gray-800;
}
body {
  @apply bg-gray-50 text-gray-950 dark:bg-gray-900 dark:text-gray-200;
}
">
<input type="hidden" name="project[description]" value="generated by https://pkg.pr.new">
<input type="hidden" name="project[template]" value="node">
<input type="hidden" name="project[title]" value="tanstack-router-react-example-navigation-blocking">
</form>
<script>document.getElementById("mainForm").submit();</script>

</body></html>