DEV Community

Cover image for TanStack Router: Nesting & 404 pages
Leonardo Montini for This is Learning

Posted on • Updated on • Originally published at leonardomontini.dev

TanStack Router: Nesting & 404 pages

Welcome to the fifth article of a series where we will explore TanStack Router, the new typesafe routing library (and state manager, in some cases) for React.

Today's topic is a few tips and tricks for nesting and managing routes.

Nesting Routes

We saw that in the file-based approach, nesting a page inside some folders will automatically create a nested route. This is a great feature that allows you to organize your project in a more structured way.

For example a file that is inside src/routes/admin/dashboard.tsx will be accessible at /admin/dashboard.

However, in some cases you might have some folders you don't want to be part of the URL. Let's see what you can do

Hidden path

This is the simplest way, assuming you only want to group some pages together but you don't want to expose the folder name in the URL: make sure to rename your folder enclosing it in parentheses.

For example, if you have a folder src/routes/(admin)/dashboard.tsx, the route will be /dashboard.

Common layout (visible)

In some cases, having routes grouped inside a folder is not only to organize the code but also to wrap all of them inside a common layout, for example a navigation bar or some kind of framing.

Let's take this example:

// src/routes/(hidden-folder)/layouts/visibleLayout.tsx
export const Route = createFileRoute('/(hidden-folder)/layouts/visibleLayout')({
  component: () => (
    <div>
      <p>This layout is visible in the URL 👀</p>
      <Link to="/layouts/visibleLayout/foo">Foo</Link> <Link to="/layouts/visibleLayout/bar">Bar</Link>
      <hr />
      <Outlet />
    </div>
  ),
});
Enter fullscreen mode Exit fullscreen mode

This is the layout that will be visible in the URL, and it will wrap the children routes.

// src/routes/(hidden-folder)/layouts/visibleLayout/foo.tsx
export const Route = createFileRoute('/(hidden-folder)/layouts/visibleLayout/foo')({
  component: () => <div>Hello /(hidden-folder)/layouts/visibleLayout/foo!</div>,
});
Enter fullscreen mode Exit fullscreen mode
// src/routes/(hidden-folder)/layouts/visibleLayout/bar.tsx
export const Route = createFileRoute('/(hidden-folder)/layouts/visibleLayout/bar')({
  component: () => <div>Hello /(hidden-folder)/layouts/visibleLayout/bar!</div>,
});
Enter fullscreen mode Exit fullscreen mode

In this case, the routes will be /layouts/visibleLayout/foo and /layouts/visibleLayout/bar and they will share the two links to navigate between them.

Common layout (hidden)

If you want to have a common layout but you don't want it to be visible in the URL, you can use the same approach as before but make sure to add an underscore _ before the folder name and the layout name.

src/routes/(hidden-folder)/layouts/_hiddenLayout.tsx
src/routes/(hidden-folder)/layouts/_hiddenLayout/foo.tsx
src/routes/(hidden-folder)/layouts/_hiddenLayout/bar.tsx
Enter fullscreen mode Exit fullscreen mode

In this case, the routes will be layouts/foo and layouts/bar.

Dot notation

Having all routes nested inside folder is handy for someone, but might be confusing if you have multiple levels of nesting that are only there to have a certain url.

For example, you might want to achieve a route that is /admin/new/dashboard/overview but you don't want to have all these folders in your project structure.

Your filename can be:

src/routes/admin.new.dashboard.overview.tsx
Enter fullscreen mode Exit fullscreen mode

And the great news is that you don't have to choose between having a flat structure or a nested one, you can mix them as you like.

404 pages

Grouping and nesting pages is cool, but what happens if the user hits an url that is not mapped to any route? You can customize the 404 page!

One of the properties of the createRouter function you're probably using in App.tsx to create your router defaultNotFoundComponent.

As the name suggests, you can pass here a component that will be rendered when the user visits a route that cannot be mapped to any of the existing ones.

Dedicated 404 pages

The one we just saw is a global 404 page, but you can also have dedicated 404 pages for specific routes. In our layout example, let's say we want a custom 404 page if the user goes on /layouts/visibleLayout/unknown.

// src/routes/(hidden-folder)/layouts/visibleLayout.tsx
export const Route = createFileRoute('/(hidden-folder)/layouts/visibleLayout')({
  component: () => (
    <div>
      <p>This layout is visible in the URL 👀</p>
      <Link to="/layouts/visibleLayout/foo">Foo</Link> <Link to="/layouts/visibleLayout/bar">Bar</Link>
      <hr />
      <Outlet />
    </div>
  ),
  notFoundComponent: () => <div>I'm the Not found page, inside /visibleLayout</div>,
});
Enter fullscreen mode Exit fullscreen mode

By adding a notFoundComponent property to the route you have to job done!

Going to /non-existent-page will render the defaultNotFoundComponent you defined in the createRouter function, while going to /layouts/visibleLayout/non-existing-page will render the custom 404 page you defined here above.

Demo time!

You can see all these features in action in the video I published on my YouTube channel:

I hope you found this article helpful! We've seen how to nest routes and how to handle 404 pages in TanStack Router by controlling the nesting of files and folder... but... what if you wanted to achieve all of that without having to rely on the filesystem?

Stay tuned for the next article where we'll see how to use the code-based approach to define your routes!


Watch the full playlist on YouTube: TanStack Router


You can find the full code on this repository on the 05-nested-routes. Leave a ⭐️ if you found the demo code useful!



Thanks for reading this article, I hope you found it interesting!

I recently launched a GitHub Community! We create Open Source projects with the goal of learning Web Development together!

Join us: https://github.com/DevLeonardoCommunity

Do you like my content? You might consider subscribing to my YouTube channel! It means a lot to me ❤️
You can find it here:
YouTube

Feel free to follow me to get notified when new articles are out ;)

Top comments (0)