React
Vite, react-router, TanStack, or no router at all.
The router adapter
Cairn is not a Next library. Everything route-related — resumeAt, handoffRoutes, pauseRoutes, the route advance rule — goes through one two-method interface.
type RouterAdapter = {
usePathname(): string;
navigate(href: string): void;
};That is the entire surface. Any router is about ten lines.
react-router
src/router-adapter.ts
import { useLocation, useNavigate } from "react-router-dom";
import type { RouterAdapter } from "@cairnkit/react";
export function useReactRouterAdapter(): RouterAdapter {
const navigate = useNavigate();
return {
usePathname: () => useLocation().pathname,
navigate: (href) => navigate(href),
};
}TanStack Router
import { useRouterState, useNavigate } from "@tanstack/react-router";
import type { RouterAdapter } from "@cairnkit/react";
export function useTanStackAdapter(): RouterAdapter {
const navigate = useNavigate();
return {
usePathname: () => useRouterState({ select: (s) => s.location.pathname }),
navigate: (href) => navigate({ to: href }),
};
}No router at all
A single-page app with no routing still works — every route feature simply never fires.
const staticAdapter = {
usePathname: () => "/",
navigate: () => {},
};Mounting
src/App.tsx
import { BrowserRouter } from "react-router-dom";
import { CairnProvider } from "@cairnkit/react";
import { CairnOverlay, TourLauncher } from "@cairnkit/ui";
import "@cairnkit/ui/styles.css";
import { useReactRouterAdapter } from "./router-adapter";
import { flows } from "./walkthrough/flows";
function Shell() {
return (
<CairnProvider flows={flows} router={useReactRouterAdapter()}>
<Routes>{/* ... */}</Routes>
<CairnOverlay />
<TourLauncher flowId="onboarding" />
</CairnProvider>
);
}
export const App = () => (
<BrowserRouter>
<Shell />
</BrowserRouter>
);Vite notes
- Import the stylesheet once, anywhere:
import "@cairnkit/ui/styles.css". - If you develop Cairn alongside your app via a workspace link, add
resolve.dedupe: ["react", "react-dom"]— symlinked packages can otherwise resolve a second copy of React and hooks break.
A complete working example lives in examples/react-vite.