Skip to content

TanStack Solid Router Demo

Examples / @xmachines/play-tanstack-solid-router-demo

Solid + @tanstack/solid-router demonstration of the Play architecture with TanStack router integration.

What This Demonstrates

  • Shared auth machine reused without framework-specific business logic
  • PlayRouterProvider renderer-based integration with TanStack Router
  • Shell-driven rendering via PlayRenderer with actor-authoritative navigation
  • Object-based routing and deep location observation using TanStack’s Solid primitives
  • Non-browser invariant tests plus browser E2E coverage

Running the Demo

From this directory (packages/play-tanstack-solid-router/examples/demo):

Terminal window
npm install
npm run dev

Open http://localhost:5173.

Step-by-Step Code Flow

Use this order to understand the implementation:

  1. src/main.tsx bootstraps the demo app and mounts <App />.
  2. src/App.tsx sets up actor lifecycle, route mapping, and TanStack Solid router integration.
  3. Shared machine/catalog logic comes from the common demo module to keep business logic framework-agnostic.
  4. Router infrastructure stays passive: it forwards navigation intent to the actor via the PlayRouterProvider and reflects actor-approved route changes back to TanStack.
  5. Shell (inside src/App.tsx) renders actor-projected state (PlayRenderer) and emits actor events.
  6. test/library-pattern.test.ts plus test/browser/ verify invariants and browser routing behavior.
// src/main.tsx (shape)
render(() => <App />, document.getElementById("root")!);
// src/App.tsx (shape)
const routeTree = extractMachineRoutes(authMachine);
const routeMap = createRouteMap(authMachine);
return (
<PlayRouterProvider
actor={actor}
router={router}
routeMap={routeMap}
renderer={(currentActor, currentRouter) => (
<Shell actor={currentActor} router={currentRouter} />
)}
/>
);
// src/components/Login.tsx (shape)
<button onClick={() => actor.send({ type: "auth.login", username, password })}>Login</button>

Key Files

  • src/App.tsx - Wires actor lifecycle, route map, TanStack router setup, and provider/renderer integration.
  • src/main.tsx - Vite bootstrap for the Solid TanStack demo.
  • src/components/ - Demo views that dispatch machine events.
  • test/library-pattern.test.ts - Invariant and architecture checks for package behavior.
  • test/browser/startup.browser.test.ts - Browser startup and wiring checks.
  • test/browser/auth-flow.browser.test.ts - Browser auth + route-flow checks.

State Machine & Architecture Details

The demo utilizes XMachines architectural invariants:

  1. Actor Authority: When a user clicks a link, TanStack Router updates the location object. The PlayRouterProvider intercepts this, translates it to a play.route event, and sends it to the actor. The actor evaluates guards and applies state transitions.
  2. Passive Infrastructure: The router does not execute route loaders or guards for business logic. The actor dictates whether navigation is permitted.
  3. Signal-Only Reactivity: The bridge leverages Solid’s createEffect and TanStack’s router.subscribe to effortlessly observe location changes and signal updates.

Watcher Lifecycle and Cleanup Contract

This demo follows the canonical watcher lifecycle:

  1. notify
  2. queueMicrotask
  3. getPending()
  4. Read actor signals and trigger state updates
  5. Re-arm with watch()/watch(...signals)

In Solid, this is largely abstracted by createEffect within the bridge adapter. Cleanup remains explicit: the provider executes bridge.disconnect() on unmount (onCleanup) to prevent ghost subscriptions, ensuring safe component teardown and hot module replacement.

Adapter Boundaries

The TanStack Solid adapter wraps TanStack’s router.navigate({ to }) and router.subscribe methods while delegating core synchronization policy to RouterBridgeBase. This keeps complex double-dispatch logic normalized across all frameworks.

Available Scripts

Terminal window
npm run dev # Start Vite dev server (default: http://localhost:5173)
npm run build # Build production assets
npm run preview # Preview production build locally
npm run test # Run unit/integration tests via Vitest
npm run test:browser # Run browser-mode tests via vitest.browser.config.ts

Verification

Use these checks from this directory:

Terminal window
npm run test
npm run test:browser

Manual sanity check:

  1. Start with npm run dev.
  2. Open http://localhost:5173.
  3. Verify login/logout transitions and URL updates remain actor-driven, including protected route redirection.

Learn More