In this blog post, I’ll guide you through the steps of integrating Shadcn UI and TanStack Router into your React.js project. Personally, I enjoy exploring the latest and trending libraries, and as of now, both Shadcn UI and TanStack Router are quickly becoming popular in the developer community. That’s why I wanted to write this article to show you how to set them up in a React.js project.

In a future post, we’ll also cover how to implement JSON Web Token (JWT) authentication and integrate it with a backend API that supports JWT.

More practice:

How to Use Shadcn UI and TanStack Router in React.js

What is Shadcn UI?

Before we jump into the setup, let’s take a moment to understand what Shadcn UI is all about. Simply put, Shadcn UI is a modern, highly customizable, and developer-friendly component library designed for building user interfaces in React applications.

It features pre-designed, accessible components built on Radix UI primitives and styled with the power and flexibility of Tailwind CSS. To get the most out of Shadcn UI, I recommend visiting the official website and exploring the available components.

What is TanStack Router?

TanStack Router is a powerful, fully type-safe, and framework-agnostic routing solution designed for React and other frameworks. As part of the TanStack family, it offers advanced features like built-in data fetching, stale-while-revalidate caching, and first-class support for search parameter APIs, making it an excellent choice for building modern, dynamic applications.

Installing and Setting Up Shadcn UI for Your React Project

For this guide, we’ll use Vite to scaffold the React.js project. If you’re unfamiliar with Vite, it’s a modern front-end build tool that enhances the developer experience by offering faster builds and optimized workflows for frameworks like React, Vue, Svelte, or plain JavaScript.

Now, I know many developers are accustomed to using create-react-app (CRA), but it’s worth noting that CRA is no longer the go-to choice for most developers. Its slower performance and outdated tooling have made modern options like Vite a far better alternative.

Create a New React.js Project

If you already have a React.js project set up with Vite as its module bundler, you can skip this step. Otherwise, open a terminal in the directory where you want to store your project’s source code and run the following command to scaffold a new project.


pnpm create vite@latest
# or
npm create vite@latest
# or
yarn create vite

Follow the prompts and select all the options for the configuration:

  • First, specify the project name.
  • Select React as the framework.
  • Choose TypeScript as the variant
scaffolding the reactjs project with vite for the auth implementation

Now that the project has been generated, follow the instructions displayed in the terminal. First, navigate into the project directory using the cd command, and then run pnpm install to install all the required dependencies.

Once the installation is complete, start the development server by running pnpm run dev. This will launch the application on port 5173. Simply open your browser and go to http://localhost:5173/ to view the default Vite welcome page.

default vite welcome page for reactjs

Add Tailwind and its configuration

Shadcn UI components are styled using Tailwind CSS, so the next step is to set up Tailwind in your project. To do this, we need to install Tailwind CSS and its required peer dependencies. Simply run the following commands to get everything configured.


pnpm add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
# or
yarn add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
# or
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Once both commands have been executed, two files— postcss.config.js and tailwind.config.js—will be generated and added to your codebase.

install tailwind css and its peer dependencies

Next, we need to include the Tailwind CSS directives in our src/index.css file. Open this file and add the following code:


@tailwind base;
@tailwind components;
@tailwind utilities;

Here’s why the Tailwind CSS directives should be included in your stylesheet:

  1. @tailwind base; – Injects Tailwind’s base styles, which reset and normalize browser styles for a consistent starting point.
  2. @tailwind components; – Adds reusable classes and pre-built component styles.
  3. @tailwind utilities; – Adds the utility classes generated by Tailwind.

Next, you need to specify the paths to all your template files in the tailwind.config.js file. Open the file and either modify it as needed or replace its content with the configuration below, especially if you started with a new Vite project:


/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
}

Configure path aliases

With the Tailwind CSS configuration complete, the next step is to set up path aliases in the project. If you’re new to React, you might not be familiar with path aliases, but they offer numerous advantages.

The most notable benefit is that instead of writing lengthy and complex relative paths like ../../../components/Button, you can use a concise and clear alias, such as @components/Button. This makes your code more readable and easier to maintain.

To configure path aliases in a React.js project created with Vite, you’ll need to update three files: tsconfig.json, tsconfig.app.json, and vite.config.ts.

Step 1: Update tsconfig.json

Begin by opening the tsconfig.json file and replacing its contents with the following configuration:


{
  "files": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.node.json"
    }
  ],
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

This configuration sets up the base URL for the project and defines the alias @/ to map to the src directory.

Step 2: Update tsconfig.app.json

To enable your IDE to resolve the path aliases, add the following configuration to the tsconfig.app.json file:


{
  "compilerOptions": {
    // ...
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "./src/*"
      ]
    }
    // ...
  }
}

Step 3: Configure vite.config.ts for Path Aliases

To ensure your app resolves path aliases correctly, follow the instructions below:

Install the @types/node package to enable the use of the path module without errors:


# (so you can import "path" without error)
npm i -D @types/node
# or
yarn add -D @types/node
# or
pnpm add -D @types/node

Update the vite.config.ts file with the following code:


import path from "path"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
})

Initialize Shadcn/UI

After setting up Tailwind CSS and path aliases in your project, we are now ready to initialize Shadcn UI. To do this, we’ll use the Shadcn UI CLI. Run the following command to begin the initialization process:


pnpm dlx shadcn@latest init
# or
npx shadcn@latest init

You will be prompted to select configuration options. The choices you make will be saved in a components.json file, which stores all the settings and preferences for the Shadcn UI components in your project. You can use the default pre-selected options, as shown in the screenshot below:

initialize shadcn ui in the vite reactjs project

Add Your First Shadcn/UI Component

Wow, that’s a lot of configuration! With Shadcn now set up in the project, we can move on to using the Shadcn UI components.

To keep things simple, we’ll start by using the Button component to build a counter. This counter will have three buttons: one to increment, one to decrement, and one to reset the count. To add the Shadcn Button component to your project, run the following command:


pnpm dlx shadcn@latest add button
# or
npx shadcn@latest add button

This command will create a UI folder within the components directory, where all the Shadcn UI components will be stored.

files and folder structure of the vite reactjs shadcn ui project

Now that the Shadcn button component has been added to the project, we can build the counter component. To do so, open the src/App.tsx file and replace its existing content with the code provided below:


import { useState } from "react";
import "./App.css";
import { Button } from "./components/ui/button";

function App() {
  const [count, setCount] = useState(0);

  return (
    <>
      <h1>Vite + React</h1>
      <div className="mt-5">
        <div className="text-center font-bold text-4xl mb-4">{count}</div>
        <div className="space-x-4">
          <Button
            variant="default"
            onClick={() => setCount((count) => count + 1)}
          >
            Increase count
          </Button>
          <Button
            variant="outline"
            onClick={() => setCount((count) => count - 1)}
          >
            Decrease count
          </Button>
          <Button variant="destructive" onClick={() => setCount(0)}>
            Reset count
          </Button>
        </div>
      </div>
    </>
  );
}

export default App;

To view the counter app, start the Vite development server and open the provided URL in your browser.

create a counter component with shadcn button components and reactjs

How to Integrate TanStack Router into Your React Application

In this section, we’ll integrate TanStack Router into our React project. As TanStack Router is fully type-safe and we’re using TypeScript, we’ll take advantage of its type safety for better accuracy and fewer errors.

TanStack Router provides two routing approaches: file-based routing, similar to Next.js, and code-based routing, like in libraries such as React Router. For simplicity, we’ll use the code-based routing approach. However, you can explore file-based routing and other features of TanStack Router in their documentation.

Install & Configure TanStack Router

First, we need to install TanStack Router. Open your terminal and run the appropriate command based on your preferred package manager:


npm install @tanstack/react-router
# or
pnpm add @tanstack/react-router
# or
yarn add @tanstack/react-router
# or
bun add @tanstack/react-router

Create a Root Route

Next, let’s initialize the TanStack Router by setting up a root route for your application’s route tree. In the src/lib/ directory, create a file named routes.tsx and add the following code:

src/lib/routes.tsx


import { createRootRoute } from "@tanstack/react-router";

export const rootRoute = createRootRoute();

export const routeTree = rootRoute.addChildren([]);

  • createRootRoute() – This method creates a new root route, which serves as the starting point for your application’s navigation hierarchy.
  • rootRoute.addChildren([]) – This method adds child routes to the root route. Currently, the array is empty, but we will add routes to it later as we build out the application’s navigation.
  • routeTree – Defines the routing structure of the app

Render the Route Provider

With the root route and route tree defined, we can now create the router object and use it to render the RouterProvider. Open the src/App.tsx file and replace its content with the following code:

src/App.tsx


import "./App.css";
import { createRouter, RouterProvider } from "@tanstack/react-router";
import { routeTree } from "./components/route-root";

const router = createRouter({ routeTree });

declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}

function App() {
  return <RouterProvider router={router} />;
}

export default App;

We utilized TypeScript’s declaration merging feature to register the router instance, ensuring type safety.

Create the Routes

Let’s create a couple of pages for navigation: Home and Dashboard. Create a new component for the home page:

src/pages/home.tsx


import { rootRoute } from "@/lib/routes";
import { createRoute } from "@tanstack/react-router";

export const homeRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: "/",
  component: Home,
});

function Home() {
  return <h2 className="font-bold text-2xl">🏡 Home Page</h2>;
}

export default Home;

Create another component for the dashboard page:

src/pages/dashboard.tsx


import { rootRoute } from "@/lib/routes";
import { createRoute } from "@tanstack/react-router";

export const dashboardRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: "/dashboard",
  component: Dashboard,
});

function Dashboard() {
  return <h2 className="font-bold text-2xl">🛹 Dashboard Page</h2>;
}

export default Dashboard;

You may have noticed that instead of exporting the components directly from their respective files, we used the createRoute() function to define routes for them and exported the routes instead.

Register the Routes

With the routes exported, we can now import them into the src/lib/routes.tsx file and add them to the array inside the rootRoute.addChildren([]) function.

src/lib/routes.tsx


import Layout from "@/components/layout";
import { dashboardRoute } from "@/pages/dashboard";
import { homeRoute } from "@/pages/home";
import { createRootRoute } from "@tanstack/react-router";

export const rootRoute = createRootRoute({
  component: Layout,
});

export const routeTree = rootRoute.addChildren([homeRoute, dashboardRoute]);

We also include the Layout component in the createRootRoute function, which we need to create.

Create a Layout Component

Creating the Layout component allows us to render the navigation menus above all the components that are descendants of the layout. We will use the Outlet component to achieve this.

To create the Layout component, navigate to the components directory and create a new file named layout.tsx. Then, add the following code to the file:

src/components/layout.tsx


import { Link, Outlet } from "@tanstack/react-router";
import { Button } from "./ui/button";

function Layout() {
  return (
    <>
      <nav className="mb-5">
        <Button asChild variant="link">
          <Link to="/" activeProps={{ className: "font-bold" }}>
            Home
          </Link>
        </Button>
        <Button asChild variant="link">
          <Link to="/dashboard" activeProps={{ className: "font-bold" }}>
            Dashboard
          </Link>
        </Button>
      </nav>
      <main>
        <Outlet />
      </main>
    </>
  );
}

export default Layout;

When you open the application in your browser, you should be able to navigate to the pages we created by clicking the navigation links.

preview the home and dashboard pages of the shadcn and tanstack router set up

Conclusion

We’re finally done! In this comprehensive guide, you learned how to set up Shadcn UI and TanStack Router in a React.js project. I hope you found this tutorial both helpful and enjoyable. If you have any questions, feel free to leave them in the comments below. Thanks for reading!