All skills
remix-run avatar

/react-router-data-mode

@df990ec
by Remixremix-run/agent-skills136 stars
4

Build React applications using React Router's data mode with createBrowserRouter and RouterProvider. Use when working with route objects, loaders, actions, Form, useFetcher, or pending/optimistic UI without the Vite plugin.

Use this Skill: https://skilld.dev/gh/remix-run/agent-skills/react-router-data-mode

This session only. Nothing lands on disk.

referencesrouting.md

≈1.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Routing

Routes are configured as JavaScript objects and passed to createBrowserRouter.

Basic Setup

import { createBrowserRouter, RouterProvider } from "react-router";

const router = createBrowserRouter([
  {
    path: "/",
    Component: Root,
    children: [
      { index: true, Component: Home },
      { path: "about", Component: About },
      {
        path: "dashboard",
        Component: Dashboard,
        children: [
          { index: true, Component: DashboardHome },
          { path: "settings", Component: Settings },
        ],
      },
    ],
  },
]);

ReactDOM.createRoot(document.getElementById("root")).render(
  <RouterProvider router={router} />
);

Route Object Properties

Property Purpose
path URL segment to match
Component React component to render
children Nested routes
index Default child route (no path segment)
loader Data loading function
action Form submission handler

See route-object.md for all properties.

Nested Routes

Child routes render inside the parent's <Outlet />:

import { Outlet } from "react-router";

const router = createBrowserRouter([
  {
    path: "/",
    Component: Root,
    children: [
      { path: "teams", Component: Teams },
      { path: "projects", Component: Projects },
    ],
  },
]);

function Root() {
  return (
    <div>
      <nav>
        <Link to="/teams">Teams</Link>
        <Link to="/projects">Projects</Link>
      </nav>
      <main>
        <Outlet />
      </main>
    </div>
  );
}

Parent path is automatically included in children: /teams and /projects.

Deeply Nested Routes

const router = createBrowserRouter([
  {
    path: "/",
    Component: Root,
    children: [
      {
        path: "dashboard",
        Component: Dashboard,
        children: [
          { index: true, Component: DashboardHome },
          { path: "settings", Component: Settings },
          { path: "profile", Component: Profile },
        ],
      },
    ],
  },
]);

Creates: /dashboard, /dashboard/settings, /dashboard/profile.

Layout Routes

Layout routes have no path - they only provide UI wrapper via <Outlet />:

const router = createBrowserRouter([
  {
    path: "/",
    Component: Root,
    children: [
      {
        // No path - this is a layout route
        Component: AuthLayout,
        children: [
          { path: "login", Component: Login },
          { path: "register", Component: Register },
        ],
      },
    ],
  },
]);

function AuthLayout() {
  return (
    <div className="auth-container">
      <Outlet />
    </div>
  );
}

Both /login and /register render inside AuthLayout.

Index Routes

Index routes render at the parent's URL (default child):

const router = createBrowserRouter([
  {
    path: "/",
    Component: Root,
    children: [
      { index: true, Component: Home }, // Renders at /
      {
        path: "dashboard",
        Component: Dashboard,
        children: [
          { index: true, Component: DashboardHome }, // Renders at /dashboard
          { path: "settings", Component: Settings }, // Renders at /dashboard/settings
        ],
      },
    ],
  },
]);

Index routes cannot have children.

Dynamic Segments

Segments starting with : are dynamic and available via useParams or params:

const router = createBrowserRouter([
  {
    path: "/teams/:teamId",
    loader: async ({ params }) => {
      return fetchTeam(params.teamId);
    },
    Component: Team,
  },
]);

function Team() {
  const { teamId } = useParams();
  const data = useLoaderData();
  return <h1>Team {teamId}: {data.name}</h1>;
}

Multiple dynamic segments:

{ path: "c/:categoryId/p/:productId", Component: Product }
// params: { categoryId: string; productId: string }

Optional Segments

Add ? to make a segment optional:

{ path: ":lang?/categories", Component: Categories }
// Matches /categories and /en/categories

{ path: "users/:userId/edit?", Component: User }
// Matches /users/123 and /users/123/edit

Splats (Catch-All)

Match any remaining path with *:

const router = createBrowserRouter([
  {
    path: "/files/*",
    loader: async ({ params }) => {
      const filePath = params["*"]; // e.g., "docs/intro.md"
      return getFile(filePath);
    },
    Component: FileBrowser,
  },
]);

404 Catch-All

const router = createBrowserRouter([
  {
    path: "/",
    Component: Root,
    children: [
      // ... other routes
      {
        path: "*",
        Component: NotFound,
      },
    ],
  },
]);

function NotFound() {
  return <h1>Page not found</h1>;
}

Anti-Pattern: Flat Routes

// ❌ DON'T: Flat structure with no shared layouts
const router = createBrowserRouter([
  { path: "/dashboard", Component: Dashboard },
  { path: "/dashboard/settings", Component: DashboardSettings },
  { path: "/dashboard/profile", Component: DashboardProfile },
]);

// ✅ DO: Use nested routes with shared layout
const router = createBrowserRouter([
  {
    path: "/dashboard",
    Component: DashboardLayout,
    children: [
      { index: true, Component: Dashboard },
      { path: "settings", Component: Settings },
      { path: "profile", Component: Profile },
    ],
  },
]);

See Also

Source: SKILL.md on GitHub

1 warning15d5 checks · Risk SAFE
  • Gen Agent Trust Hub15d

    This skill provides official documentation and best-practice code patterns for implementing React Router Data Mode. It is authored by the official maintainers and contains no malicious content or security threats.

  • Socket15d

    No alerts

  • Snyk15d

    Risk: LOW · No issues

  • Runlayer7mo

    8/8 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at df990ec. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last week.

Steadyupdated 8 months ago

README badge

README badge for remix-run/agent-skills/react-router-data-mode