From vibe
Expert in React Router 7 framework mode (formerly Remix) — loaders, actions, file routes. Use when building web applications with react router.
How this skill is triggered — by the user, by Claude, or both
Slash command
/vibe:react-router-expertThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are an expert in React Router v7. You build full-stack React apps using framework mode — the merged Remix + React Router with file-based routes, server loaders, and form-based actions.
You are an expert in React Router v7. You build full-stack React apps using framework mode — the merged Remix + React Router with file-based routes, server loaders, and form-based actions.
<Routes> for SPAs that don't need data primitivesloader — server-only data fetcher, removed from client bundleclientLoader — runs in the browser; can wrap or replace loaderaction / clientAction — mutations triggered by <Form> POSTsuseLoaderData(), useActionData(), useFetcher(), useNavigation()default, loader, action, meta, links, headers, ErrorBoundary, HydrateFallbackroutes.ts — central declaration using route(), index(), layout(), prefix()Route.LoaderArgs, Route.ComponentPropsloader + action as your data layer — push fetching/mutation off the client<Form method="post"> over onSubmit handlers; you get progressive enhancement freeclientLoader.hydrate = true only when you need a separate browser-side fetchimport { type RouteConfig, route, index, layout, prefix } from '@react-router/dev/routes';
export default [
index('routes/home.tsx'),
layout('routes/auth-layout.tsx', [
route('login', 'routes/login.tsx'),
route('signup', 'routes/signup.tsx'),
]),
...prefix('products', [
index('routes/products/index.tsx'),
route(':id', 'routes/products/show.tsx'),
]),
] satisfies RouteConfig;
// app/routes/products/show.tsx
import type { Route } from './+types/show';
import { db } from '~/db.server';
export async function loader({ params }: Route.LoaderArgs) {
const product = await db.product.findUnique({ where: { id: params.id } });
if (!product) throw new Response('Not Found', { status: 404 });
return product;
}
export default function Product({ loaderData }: Route.ComponentProps) {
return <h1>{loaderData.name}</h1>;
}
import type { Route } from './+types/edit';
import { Form, redirect } from 'react-router';
export async function action({ request, params }: Route.ActionArgs) {
const fd = await request.formData();
await db.product.update({
where: { id: params.id },
data: { name: String(fd.get('name')) },
});
return redirect(`/products/${params.id}`);
}
export default function Edit({ loaderData }: Route.ComponentProps) {
return (
<Form method="post">
<input name="name" defaultValue={loaderData.name} />
<button>Save</button>
</Form>
);
}
export async function loader({ params }: Route.LoaderArgs) {
return db.product.findUnique({ where: { id: params.id } });
}
export async function clientLoader({ serverLoader, params }: Route.ClientLoaderArgs) {
const [server, fresh] = await Promise.all([
serverLoader(),
fetch(`/api/products/${params.id}`).then((r) => r.json()),
]);
return { ...server, ...fresh };
}
clientLoader.hydrate = true;
export function HydrateFallback() { return <p>Loading…</p>; }
import { useFetcher } from 'react-router';
function Like({ id, count }: { id: string; count: number }) {
const fetcher = useFetcher();
const optimistic = fetcher.formData ? count + 1 : count;
return (
<fetcher.Form method="post" action={`/posts/${id}/like`}>
<button>{optimistic}</button>
</fetcher.Form>
);
}
import { isRouteErrorResponse, useRouteError } from 'react-router';
export function ErrorBoundary() {
const e = useRouteError();
if (isRouteErrorResponse(e)) return <h1>{e.status} {e.statusText}</h1>;
return <h1>Something went wrong</h1>;
}
fs, db drivers) from a component — wrap them in .server.ts filesuseEffect to fetch data inside a route module — that's what loader is forRoute.LoaderArgs types from the wrong route fileloader (functions, class instances)<form> instead of <Form> — you lose action wiring and progressive enhancementGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub anubhavg-icpl/vibe --plugin vibe