Skip to main content

Command Palette

Search for a command to run...

Quick Setup for React Router v6 in Your React App

Updated
6 min readView as Markdown
Quick Setup for React Router v6 in Your React App
D

Passionate and results-driven Full-Stack Developer with more than 4 years of experience in managing the entire application lifecycle, from design to deployment. Proficient in React.js, MERN stack, and microservice architecture, with a track record of building scalable and high-performance applications. A self-motivated technology enthusiast with an entrepreneurial mindset, dedicated to building amazing products that drive business success.

Bootstrapping application

Lets use Vite to setup our react app as it is the go to way of creating a react application as of today. Run the following command in your favorite terminal to get started. Follow the onscreen instructions. I am choosing to use React with TypeScript + SWC here.

npm create vite@latest

Installing react-router-dom

Let's install react-router-dom as our dependancy

npm install react-router-dom

Setup Shadcn/ui

I am using navigation menu from shadcn-ui which is a popular components collection from where you can directly copy-paste into your code. Let's add it via CLI, you can also choose manual. I am using Tailwind for styling here. Here is the official installation guide.

Install Tailwind

npm install -D tailwindcss postcss autoprefixer

npx tailwindcss init -p

Adding path alias

Add the following code to the tsconfig.json file to resolve paths:

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

Update vite.config.ts

npm i -D @types/node

Add the following contents to your vite.config.ts file

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

npx shadcn-ui@latest init

Add navigation menu

npx shadcn-ui@latest add navigation-menu

Notice the components/ui and lib folders create for you. That's where the navigation-menu is residing. Let's modify a bit. Add the following lines at the bottom of the file.

const ListItem = React.forwardRef<
  React.ElementRef<'a'>,
  React.ComponentPropsWithoutRef<'a'>
>(({ className, title, children, href = '/', ...props }, ref) => {
  return (
    <li>
      <NavigationMenuLink asChild>
        <Link to={href}>
          <span
            ref={ref}
            className={cn(
              'block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground',
              className
            )}
            {...props}
          >
            <div className='text-sm font-medium leading-none'>{title}</div>
            <p className='line-clamp-2 text-sm leading-snug text-muted-foreground'>
              {children}
            </p>
          </span>
        </Link>
      </NavigationMenuLink>
    </li>
  )
})

export const Navbar = () => {
  return (
    <NavigationMenu className='relative z-[1] flex w-screen justify-center'>
      <NavigationMenuList className='center shadow-blackA4 text-[#7360BF] m-0 flex list-none rounded-[6px] bg-[#181a1b] p-1 shadow-[0_2px_10px]'>
        <NavigationMenuItem>
          <NavigationMenuTrigger className='text-violet11 hover:bg-violet3 focus:shadow-violet7 group flex select-none items-center justify-between gap-[2px] rounded-[4px] px-3 py-2 text-[15px] font-medium leading-none outline-none focus:shadow-[0_0_0_2px]'>
            Getting started
          </NavigationMenuTrigger>
          <NavigationMenuContent className='bg-[#181a1b] text-white rounded-lg data-[motion=from-start]:animate-enterFromLeft data-[motion=from-end]:animate-enterFromRight data-[motion=to-start]:animate-exitToLeft data-[motion=to-end]:animate-exitToRight absolute top-0 left-0 w-full sm:w-auto'>
            <ul className='p-6 md:w-[400px] lg:w-[500px]'>
              {blogs.slice(3).map((blog) => (
                <ListItem
                  key={blog.title}
                  title={blog.title}
                  href={`/${blog.id}`}
                >
                  {blog.description}
                </ListItem>
              ))}
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>

        <NavigationMenuItem>
          <NavigationMenuTrigger className='text-violet11 hover:bg-violet3 focus:shadow-violet7 group flex select-none items-center justify-between gap-[2px] rounded-[4px] px-3 py-2 text-[15px] font-medium leading-none outline-none focus:shadow-[0_0_0_2px]'>
            Components
          </NavigationMenuTrigger>
          <NavigationMenuContent className='bg-[#181a1b] text-white rounded-lg  absolute top-0 left-0 w-full sm:w-auto'>
            <ul className='grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] '>
              {blogs.map((blog) => (
                <ListItem
                  key={blog.title}
                  title={blog.title}
                  href={`/${blog.id}`}
                >
                  {blog.description}
                </ListItem>
              ))}
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>

        <NavigationMenuItem>
          <a href='/docs'>
            <NavigationMenuLink
              className={`text-violet11 hover:bg-violet3 focus:shadow-violet7 select-none rounded-[4px] px-3 py-2 text-[15px] font-medium leading-none no-underline outline-none focus:shadow-[0_0_0_2px] flex align-center gap-0.5 ${navigationMenuTriggerStyle()}`}
              href='https://github.com/radix-ui'
            >
              Documentation <ExternalLink size={16} />
            </NavigationMenuLink>
          </a>
        </NavigationMenuItem>
      </NavigationMenuList>
    </NavigationMenu>
  )
}

Pre-routing setup

Let's setup routing in our App.tsx file

Folder structure

We will store all our pages under routes folder instead of pages and lets create our root.tsx route. It is where we are going to setup our layout consuming our navigation menu that we added.

mkdir src/routes
touch src/routes/Root.jsx
// /src/Root.tsx
export const Root = () => {
  return (
    <div>
      <nav className='flex justify-center pt-10'>
        <Navbar />
      </nav>
      <Outlet />
    </div>
  )
}

Blog Element

Let's create blog which will be the element that we render in our route.

// src/Blog.tsx
import { useParams } from 'react-router-dom'
import { blogs } from '../data'

export const Blog = () => {
  const { id: currentId } = useParams()
  const blog = blogs.find(({ id }) => currentId === id)
  if (!blog) {
    throw new Response('', {
      status: 404,
      statusText: 'Not Found',
    })
  }
  return (
    <main className='flex justify-center'>
      <section className='mt-10 w-7/12 h-fit bg-[#181a1b] rounded-xl text-white p-5 text-center'>
        <h1 className='text-[#7360BF] text-3xl'>{blog.title}</h1>
        <p className='p-2 mt-4 text-lg text-left leading-8'>{blog.content}</p>
      </section>
    </main>
  )
}

Stub blog data

Let's add some stub data for blogs

// /src/data/index.ts
const content = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lobortis mattis aliquam faucibus purus in massa tempor nec feugiat. Nec dui nunc mattis enim ut tellus. Nulla at volutpat diam ut. Erat pellentesque adipiscing commodo elit. Fringilla ut morbi tincidunt augue interdum velit euismod in. Eleifend quam adipiscing vitae proin sagittis nisl. Eget nullam non nisi est. Interdum consectetur libero id faucibus nisl tincidunt eget nullam non. Cursus risus at ultrices mi tempus imperdiet. Lectus sit amet est placerat. Sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus. Penatibus et magnis dis parturient montes nascetur. Senectus et netus et malesuada fames ac turpis egestas. Phasellus faucibus scelerisque eleifend donec pretium vulputate sapien nec sagittis. Ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas. Etiam erat velit scelerisque in. Malesuada proin libero nunc consequat interdum. Purus ut faucibus pulvinar elementum integer enim neque.

Consequat nisl vel pretium lectus quam. Sit amet cursus sit amet dictum. Ornare arcu dui vivamus arcu felis bibendum ut tristique et. Morbi blandit cursus risus at ultrices mi tempus. Elit pellentesque habitant morbi tristique senectus et. Leo duis ut diam quam nulla porttitor. Platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper. Viverra ipsum nunc aliquet bibendum enim facilisis gravida. Scelerisque in dictum non consectetur a erat nam at. Auctor urna nunc id cursus metus aliquam eleifend. Sem integer vitae justo eget magna fermentum.`

export const blogs: {
  id: string
  title: string
  category: string
  description: string
  content: string
}[] = [
  {
    id: 'f17c03e0-3f5c-4b61-99b6-efcc347dfe52',
    title: 'Understanding JavaScript Closures',
    category: 'JavaScript',
    description:
      'An in-depth look at closures in JavaScript and how to use them effectively.',
    content,
  },
  {
    id: '7bcbcad1-c469-419e-a0f8-fabed6cf153b',
    title: 'A Guide to Responsive Web Design',
    category: 'Web Design',
    description:
      'Learn the principles and techniques of responsive web design to create websites that look great on all devices.',
    content,
  },
  {
    id: '0e332425-b4f3-4887-b924-35bd10de44be',
    title: 'Exploring Python Decorators',
    category: 'Python',
    description:
      'Discover the power of decorators in Python and how they can be used to modify the behavior of functions.',
    content,
  },
  {
    id: 'd5be6ade-be0f-4588-b474-aa9381f7f669',
    title: 'Mastering CSS Grid Layout',
    category: 'CSS',
    description:
      'A comprehensive guide to CSS Grid Layout, a powerful layout system available in CSS.',
    content,
  },
  {
    id: 'c5ac15e4-8806-4fcc-b75a-53e341693da7',
    title: 'Building RESTful APIs with Node.js',
    category: 'Node.js',
    description:
      'Learn how to build scalable and efficient RESTful APIs using Node.js and Express.',
    content,
  },
]

Handling 404

Let's also create a component to render when for handling broken links

import { FC } from 'react'

type NotFoundProps = {
  message?: string
}
const NotFound: FC<NotFoundProps> = ({ message }) => {
  return <div>{message || 'Oops, page not found!'}</div>
}

export default NotFound

Setup Router

Let's add the router to App.tsx, I am using createBrowserRouter as it is the recommended for web projects like this one.

// src/App.tsx

import { RouterProvider, createBrowserRouter } from 'react-router-dom'
import { Root } from '@/routes/Root'
import { useMemo } from 'react'
import NotFound from './routes/NotFound'
import { Blog } from './routes/Blog'

function App() {
  const router = useMemo(
    () =>
      createBrowserRouter([
        {
          path: '/',
          element: <Root />,
          children: [
            {
              path: '/:id',
              element: <Blog />,
            },
          ],
          errorElement: (
            <NotFound message='Sorry, blog with give ID not found!' />
          ),
        },
        {
          path: '*',
          element: <NotFound />,
        },
      ]),
    []
  )
  return (
    <div className='h-screen bg-gradient-to-r from-violet-500 to-fuchsia-500'>
      <RouterProvider router={router} />
    </div>
  )
}

export default App

Demo

Github repo

You can find the full code in my GitHub repo

References