Featured resource
2026 Tech Forecast
2026 Tech Forecast

Stay ahead of what’s next in tech with predictions from 1,500+ business leaders, insiders, and Pluralsight Authors.

Get these insights
  • Lab
    • Libraries: If you want this lab, consider one of these libraries.
    • Core Tech
Labs

Guided: Build a Multi-page App with TanStack Router

In this Code Lab, you will build a dynamic, multi-page React application using TanStack Router. You’ll utilize key routing concepts like nested routes, URL parameters, data loading, and error handling. By the end of this lab, you will have established a simple and practical application with these concepts.

Lab platform
Lab Info
Level
Beginner
Last updated
Oct 28, 2025
Duration
30m

Contact sales

By clicking submit, you agree to our Privacy Policy and Terms of Use.
Table of Contents
  1. Challenge

    Introduction

    Welcome to this Code Lab on building a multi-page application with TanStack Router!

    TanStack Router is a modern, powerful routing library for React that emphasizes type safety, performance, and features like asynchronous data loading out of the box. In this lab, you'll build a simple blog application to explore its core concepts.


    You will start with a basic React project and incrementally add routes, layouts, data loading, and error handling. If you would like to check your implementations, you can find solutions within the solution directory. These solutions are not definitive, so don't worry about semantics such as having exact variable names, formatting, etc.

    You can also run the application at any point in the lab with npm run dev within the Terminal.

  2. Challenge

    Basic Router Configuration

    The first step is to define the structure of your application's routes and integrate the router with your React component tree. You'll define a root route which acts as the main entry point, and then create a router instance that knows about your application's pages.


    Your first priority will be to define the foundational routes for the application.

    Define the Initial Route Tree
    1. Inside the main.jsx file, find the // TODO: Task 2.1 comment.
    2. Create a rootRoute using createRootRoute(). This route will serve as the parent for all other routes.
    3. Define two child routes for the home (/) and about (/about) pages. Create and attach them to the rootRoute with createRoute({ getParentRoute: () => rootRoute, path: '', component: });
    4. For the home route, set the path to '/' and associate it with the Index component. For the about route, set the path to '/about' and associate it with the About component.
    5. Finally, assemble these routes into a routeTree by adding them as children to rootRoute with rootRoute.addChildren([indexRoute, aboutRoute]);.

    With the routes defined, you now need to create the router instance and provide it to your React application.

    Create and Provide the Router
    1. Still in src/main.jsx, locate the // TODO: Task 2.2 comments.
    2. Create a new router instance using createRouter(). When creating it, pass the routeTree you defined in the previous task to the configuration object.
    3. Find the root element rendering App. Replace the <App /> component with the <RouterProvider /> component from TanStack Router. Pass your newly created router instance to the router prop of the provider.
  3. Challenge

    Layouts and Navigation

    Most web applications have a shared layout—a common header, footer, or navigation bar. TanStack Router handles this elegantly using nested routes and an <Outlet/> component. In this step, you'll create a persistent layout and add client-side navigation.


    A layout route allows you to share UI, like a navigation bar, across multiple pages. You'll create a root component that includes navigation and a placeholder for child routes to render into.

    Create the Root Layout Component
    1. Open the src/routes/__root.jsx file and find the // TODO: Task 3.1 comment.
    2. This component needs to render the UI for its child routes. Import the Outlet component from @tanstack/react-router and render it within the main element. The Outlet acts as a placeholder where nested routes will be displayed.

    Now, you'll make the navigation interactive. Instead of standard <a> tags, TanStack Router provides a <Link> component for client-side navigation that avoids full-page reloads.

    Implement Navigation with the Link Component
    1. Still in src/routes/__root.jsx, find the // TODO: Task 3.2 comments.
    2. Import the Link component from @tanstack/react-router.
    3. Replace the <a> tags for Home, About, and Posts with the <Link> component.
    4. Set the to prop on each <Link> to the correct path: '/' for Home, '/about' for About, and '/posts' for Posts.
    5. Set the activeProps prop on each <Link> to {{ className: 'active' }}.

    With the layout component ready, you need to tell the router to use it. You'll associate the layout component with the root route.

    Connect the Layout to the Root Route
    1. Return to src/main.jsx and find the // TODO: Task 3.3 comment.
    2. Modify the rootRoute definition. Pass a configuration object to createRootRoute() and set the component property to the Root component you just worked on.
  4. Challenge

    Dynamic Routes for Blog Posts

    Static pages are great, but real applications need dynamic content. Here, you'll add routes for your blog. This includes a route to list all posts and a parameterized route to display a single post based on its ID from the URL.


    Now, add you'll add routes for the blog. You'll need one route to list all posts and another, parameterized route to show a single post.

    Define Routes for Posts
    1. In src/main.jsx, find the // TODO: Task 4.1 comments.
    2. Create a new route for /posts that will render the Posts component. Make sure it's a child of the rootRoute.
    3. Create a nested route for individual posts. This route's path should be '$postId', making it a child of the postsRoute route. The $ prefix signifies a URL parameter. This route should render the Post component.
    4. Add these routes to the route tree by adding postsRoute.addChildren([postIdRoute]) after aboutRoute.

    With the routes defined, you need to implement the components that will display the data. You'll fetch the data in a later step; for now, just set up the component structure.

    Implement the Post and Posts Components
    1. Open src/routes/posts.jsx and find // TODO: Task 4.2 and define an instance of getRouteApi() passing in the '/posts' route. Then modify the posts variable to retrieve loader data with routeApi.useLoaderData().
    2. Map over the posts array to render a list of post titles. Each title should be a <Link> pointing to that post's specific URL (e.g., /posts/1).
    3. Open src/routes/post.jsx and find // TODO: Task 4.2 and define an instance of getRouteApi() passing in the '/posts/$postId' route. Then modify the posts variable to retrieve loader data with routeApi.useLoaderData().
  5. Challenge

    Data Loading with Loaders

    One of TanStack Router's standout features is its data loading strategy. loader functions allow you to fetch data before a component renders, simplifying state management and eliminating data-fetching waterfalls. You'll now hook up your post routes to a mock API.


    Loaders are functions that fetch data before a route component renders. This is a powerful feature for handling data dependencies gracefully.

    Implement Data Loaders for Post Routes
    1. Open src/main.jsx and find // TODO: Task 5.1.
    2. Add a loader function to the /posts route definition. This function should call the fetchAllPosts function from our mock API (src/api.js) and return the result.
    3. Add another loader function to the /$postId route. This loader is special because it is an asynchronous arrow function that receives the route's params. Use params.postId to call the fetchPostById API function and return the result.
  6. Challenge

    Advanced Route Handling

    A robust application provides clear feedback to the user. In this final step, you'll implement loading indicators for when data is being fetched and create fallback UIs for when things go wrong, such as a data fetching error or a user navigating to a page that doesn't exist.


    To improve user experience, it's crucial to show a loading state while data is being fetched. TanStack Router makes this easy with the pendingComponent option.

    Add a Pending Component for Loading States
    1. Open src/main.jsx and find the // TODO: Task 6.1 comments.
    2. First, create a simple PendingComponent function that returns some loading UI, like a <div>Loading...</div>.
    3. Next, add the pendingComponent property to both the /posts route and the /$postId route definitions, assigning your new PendingComponent to them.

    Finally, you'll handle errors. What happens if a post isn't found or the API fails? You can define an errorComponent to render a fallback UI.

    Implement Error and Not Found Components
    1. Still in src/main.jsx, find // TODO: Task 6.2.
    2. Add the errorComponent property to the /$postId route. For its value, provide an inline component function that receives an error prop. This component should render a message like Error: {error.message}.
    3. To handle routes that don't exist at all, add a notFoundComponent to the rootRoute. This component should render a simple 'Not Found' message.

    After completing all of these implementations, run your application to test it. You should see three links at the top for Home, About, and Posts. While Home and About should be self-explanatory, Posts should display three mock blog posts that should each display their own text snippets (through an Outlet) when clicked.

    If your application is not behaving as expected, re-check your implementations against the provided instructions or compare them to the solutions within the solution directory. Otherwise, you've completed the lab!

About the author

George is a Pluralsight Author working on content for Hands-On Experiences. He is experienced in the Python, JavaScript, Java, and most recently Rust domains.

Real skill practice before real-world application

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Learn by doing

Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.

Follow your guide

All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.

Turn time into mastery

On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.

Get started with Pluralsight