Client-Side Routing

SkillAI & models

Your AI can add new routes to a React Router app without the app shell reloading on every navigation. This skill shows it how to keep the app shell mounted as people move between pages, fix a sidebar that reloads during navigation, and choose between the root.tsx layout and the pathless _app.tsx layout pattern.

Available today. Use it from your connected AI after setup.

After adding this skill, ask your AI to add a new route or fix navigation reloads in your React Router app. It will apply the patterns from the skill to keep the app shell mounted.

Then ask your AI: use the Client-Side Routing skill

What your AI can do with it

  • Add new routes to a React Router app without the app shell reloading
  • Keep the app shell mounted while people move between pages
  • Fix a sidebar that reloads every time navigation happens
  • Choose between the root.tsx layout and the pathless _app.tsx layout pattern

What this skill tells your AI

The instructions your AI receives, as published by builderio/agent-native in .agents/skills/client-side-routing/SKILL.md and read by ahel’s review.

Rule

All templates are single-page apps using React Router. Navigation must not remount the app shell. The agent sidebar, document tree, and any other persistent chrome must survive route changes.

Why

If the shell unmounts on every navigation, the agent chat reconnects/reloads, destroying in-progress work and hammering the backend.

Hard Rule

The app shell (AgentSidebar + any top-level navigation) must be mounted ONCE, above the <Outlet />. Never wrap each page in its own <AppLayout> / <Layout>. React sees a different component at the outlet position on each nav and unmounts the entire subtree.

Two Correct Patterns

1. All routes need the shell

Mount <AppLayout> in root.tsx around <Outlet />:

// app/root.tsx
<AppLayout>
  <Outlet />
</AppLayout>

2. Mix of protected and public routes

Use a React Router pathless layout route:

app/routes/
  _app.tsx                  # renders <AppLayout><Outlet /></AppLayout>
  _app._index.tsx           # / → under AppLayout
  _app.settings.tsx         # /settings → under AppLayout
  _app.team.tsx             # /team → under AppLayout
  book.$slug.tsx            # /book/:slug → no layout (public)
  f.$.tsx                   # /f/* → no layout (public form filler)

The _ prefix on _app.tsx makes it a pathless parent — it contributes the layout but no URL segment. Route files prefixed with _app. nest under it and share the layout instance across navigations.

Anti-Pattern

// ❌ BAD — each route wraps its own Layout, causing full remount on every nav
export default function Settings() {
  return (
    <AppLayout>
      <SettingsContent />
    </AppLayout>
  );
}

If a page needs per-route data (e.g. sidebar highlighting the active document), derive it inside the layout from useParams() / useLocation() — don't pass it as a prop through every route file.

Chat-First Routes

If / is a full-page chat such as AgentChatHome, keep the app shell mounted around it when possible so AgentSidebar URL sync and route warmup stay active. If the chat route intentionally lives outside the shell, add a tiny app-owned prewarm for the routes agents commonly open from that chat. In local dev, React Router can update the address bar before a cold Vite route chunk commits, which makes navigation look broken even when the URL is correct.

Adding a New Route

  • Pattern #1 (AppLayout in root.tsx): just render page content — nothing else.
  • Pattern #2 (pathless _app.tsx): name the file _app.<segment>.tsx for authed routes, or bare <segment>.tsx for public routes.

Related Skills

  • adding-a-feature — The four-area checklist referencing route layout patterns
  • context-awareness — Navigation state written on every route change

Signals

GitHub stars
5k
Forks
440
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
client-side-routing
Source
github.com/builderio/agent-native