You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+22-23Lines changed: 22 additions & 23 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -169,9 +169,9 @@ TypeRoute requires React 18 or higher.
169
169
170
170
# Motivation
171
171
172
-
Most React routers today either lack type safety entirely, or achieve it through build plugins and code generation. TypeRoute takes a different path: it uses TypeScript's own inference to give you full autocompletion and type checking - for routes, params, search params, navigation - without any tooling beyond the TypeScript compiler you're already running.
172
+
Most React routers today either lack type safety entirely, or achieve it through build plugins and code generation. TypeRoute takes a different path: it gives you full autocompletion and type checking - for routes, params, search params, navigation - without any tooling beyond the TypeScript compiler you're already running.
173
173
174
-
The API is deliberately small. You define routes with a builder, register them once through module augmentation, and that's it. Routes nest, middlewares compose, and types inherit down the tree. There's no config file, no CLI, no codegen step. The whole thing ships at ~4kB gzipped before tree-shaking.
174
+
The API is deliberately small. You define routes with a builder, register them once through module augmentation, and that's it. Routes nest and types inherit down the tree. There's no config file, no CLI, no codegen step. The whole thing ships at ~4kB gzipped before tree-shaking.
175
175
176
176
TypeRoute doesn't try to be a framework. It doesn't own your data fetching, your file structure, or force you into SSR. It handles routing - matching URLs to components and managing navigation - and stays out of the way for everything else.
177
177
@@ -215,19 +215,19 @@ Route building is immutable: every method on a route returns a new route instanc
215
215
216
216
# Nested routes and layouts
217
217
218
-
Any route can have child routes. Call `.route()` on an existing route to create one:
Child routes build on their parent's path. So `overview` matches `/dashboard`, `settings` matches `/dashboard/settings`, and `profile` matches `/dashboard/profile`.
228
+
`.route()` extends the path: `settings` matches `/dashboard/settings` and `profile` matches `/dashboard/profile`. Chaining `.component()` directly (like `overview`) doesn't change the path, so `overview` matches `/dashboard`.
229
229
230
-
They also nest inside the parent's component. The parent renders an `<Outlet />` to mark where child routes should appears:
230
+
All of them nest inside `dashboard`'s component. The parent renders an `<Outlet />` to mark where child routes should appear:
231
231
232
232
```tsx
233
233
function DashboardLayout() {
@@ -273,11 +273,11 @@ Beyond paths and components, child routes also inherit search param validators,
273
273
Before setting up the router, you need to collect your navigable routes into a collection (either array or record). When building nested route hierarchies, you'll often create intermediate parent routes solely for grouping and shared layouts. These intermediate routes shouldn't be included in your routes collection - only the final, navigable routes should be:
274
274
275
275
```tsx
276
-
// Intermediate route used for hierarchy
276
+
// Intermediate route used for shared layout
277
277
const layout =route("/").component(Layout);
278
278
279
279
// Navigable routes that users can actually visit
280
-
const home =layout.route("/").component(Home);
280
+
const home =layout.component(Home);
281
281
const about =layout.route("/about").component(About);
This makes sure that only actual pages can be matched and appear in autocomplete. The intermediate routes still exist as part of the hierarchy, they just aren't directly navigable. Note that the order of routes in the collection doesn't matter - TypeRoute uses a [ranking algorithm](#route-matching-and-ranking) to pick the most specific match.
290
+
This makes sure that only actual pages can be matched and appear in autocomplete. The intermediate routes still exist as part of the build chain, they just aren't directly navigable. Note that the order of routes in the collection doesn't matter - TypeRoute uses a [ranking algorithm](#route-matching-and-ranking) to pick the most specific match.
291
291
292
292
The `RouterRoot` component is the entry point to TypeRoute. It listens to URL changes, matches the current path against your routes, and renders the matching route's component hierarchy.
293
293
@@ -792,16 +792,22 @@ Note that `Navigate` uses `useLayoutEffect` internally to ensure the navigation
792
792
793
793
# Index routes
794
794
795
-
Layout routes often need a child route at `"/"` just to show default content at the parent's path:
795
+
When you have a layout route, you often want content at the layout's path when no child route matches. Since `.component()` doesn't change the path, you create an index route by chaining directly on the layout:
This is perfectly fine, but `.index()` offers a shorthand. It defines what renders when no child route matches, directly on the parent:
804
+
Here, `overview` matches `/dashboard` and renders `DashboardLayout > Overview`. Only `overview` and `settings` go in the routes collection - `dashboard` is just an intermediate used for building:
805
+
806
+
```tsx
807
+
const routes = [overview, settings];
808
+
```
809
+
810
+
`.index()` offers an alternative that combines the layout and the index content into a single navigable route:
Under the hood, `.index(Comp)` is equivalent to `.component(() => useOutlet() ?? <Comp />)`. Note that when using `.index()`, the layout route itself becomes navigable. Include it in your routes collection instead of the former child route:
820
+
Under the hood, `.index(Comp)` is equivalent to `.component(() => useOutlet() ?? <Comp />)`. It renders `Overview` when no child route matches, and the child's outlet when one does. Since the layout route is now navigable, include it in your routes collection:
822
821
823
822
```tsx
824
823
const routes = [dashboard, settings];
@@ -1264,7 +1263,7 @@ function AppLayout() {
1264
1263
}
1265
1264
1266
1265
// Page routes
1267
-
const home =app.route("/").component(() => <h1>Welcome home</h1>);
1266
+
const home =app.component(() => <h1>Welcome home</h1>);
1268
1267
const about =app.route("/about").component(() => <h1>About us</h1>);
1269
1268
1270
1269
// Router setup
@@ -1351,7 +1350,7 @@ This also works for scoped not-found pages. If you want a fallback specific to a
0 commit comments