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
PlayRouterProviderrenderer-based integration with TanStack Router- Shell-driven rendering via
PlayRendererwith 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):
npm installnpm run devOpen http://localhost:5173.
Step-by-Step Code Flow
Use this order to understand the implementation:
src/main.tsxbootstraps the demo app and mounts<App />.src/App.tsxsets up actor lifecycle, route mapping, and TanStack Solid router integration.- Shared machine/catalog logic comes from the common demo module to keep business logic framework-agnostic.
- Router infrastructure stays passive: it forwards navigation intent to the actor via the
PlayRouterProviderand reflects actor-approved route changes back to TanStack. Shell(insidesrc/App.tsx) renders actor-projected state (PlayRenderer) and emits actor events.test/library-pattern.test.tsplustest/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:
- Actor Authority: When a user clicks a link, TanStack Router updates the location object. The
PlayRouterProviderintercepts this, translates it to aplay.routeevent, and sends it to the actor. The actor evaluates guards and applies state transitions. - Passive Infrastructure: The router does not execute route loaders or guards for business logic. The actor dictates whether navigation is permitted.
- Signal-Only Reactivity: The bridge leverages Solid’s
createEffectand TanStack’srouter.subscribeto effortlessly observe location changes and signal updates.
Watcher Lifecycle and Cleanup Contract
This demo follows the canonical watcher lifecycle:
notifyqueueMicrotaskgetPending()- Read actor signals and trigger state updates
- 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
npm run dev # Start Vite dev server (default: http://localhost:5173)npm run build # Build production assetsnpm run preview # Preview production build locallynpm run test # Run unit/integration tests via Vitestnpm run test:browser # Run browser-mode tests via vitest.browser.config.tsVerification
Use these checks from this directory:
npm run testnpm run test:browserManual sanity check:
- Start with
npm run dev. - Open
http://localhost:5173. - Verify login/logout transitions and URL updates remain actor-driven, including protected route redirection.