Metronic React
Getting Started

Routing

Learn how to use and customize the routing system in Metronic React.

Metronic React uses React Router v7 for handling navigation between different pages. This guide explains the routing system architecture and how to work with it.

Routing Architecture

The routing system is organized around these key files:

  1. app-routing.tsx: Main router configuration
  2. app-routing-setup.tsx: Route definitions
  3. require-auth.tsx: Route protection component
  4. auth-routing.tsx: Authentication routes

Main Router Setup

The main router is defined in src/routing/app-routing.tsx:

// src/routing/app-routing.tsx
import { Suspense } from 'react';
import { BrowserRouter, useRoutes } from 'react-router-dom';
import { AppRoutingSetup } from './app-routing-setup';
import TopBarProgress from 'react-top-loading-bar';
import { useProgress } from '@/hooks/use-progress';
 
const Routing = () => {
  const { progress } = useProgress();
  const routes = useRoutes(AppRoutingSetup());
 
  return (
    <>
      <TopBarProgress
        color='#4338ca'
        progress={progress}
      />
      <Suspense fallback={<div>Loading...</div>}>
        {routes}
      </Suspense>
    </>
  );
};
 
export function AppRouting() {
  return (
    <BrowserRouter basename="/metronic/tailwind/react">
      <Routing />
    </BrowserRouter>
  );
}

Note the basename prop in BrowserRouter, which sets the base URL for all routes. This matches the base configuration in vite.config.ts.

Route Definitions

Routes are defined in src/routing/app-routing-setup.tsx:

// src/routing/app-routing-setup.tsx
import { ReactElement } from 'react';
import { Navigate, Route, Routes } from 'react-router';
import { DefaultPage } from '@/pages/dashboards';
import { RequireAuth } from '@/auth/require-auth';
import { Demo3Layout } from '@/layouts/demo3/layout';
import { ErrorRouting } from '@/errors/error-routing';
import { AuthRouting } from '@/auth/auth-routing';
 
const AppRoutingSetup = (): ReactElement => {
  return (
    <Routes>
      <Route element={<RequireAuth />}>
        <Route element={<Demo3Layout />}>
          <Route path="/" element={<DefaultPage />} />
          {/* Other protected routes... */}
        </Route>
      </Route>
      <Route path="error/*" element={<ErrorRouting />} />
      <Route path="auth/*" element={<AuthRouting />} />
      <Route path="*" element={<Navigate to="/error/404" />} />
    </Routes>
  );
};
 
export { AppRoutingSetup };

Protected Routes

Routes that require authentication are wrapped with the RequireAuth component:

// src/auth/require-auth.tsx
import { useEffect } from 'react';
import { useNavigate, Outlet } from 'react-router-dom';
import { useAuth } from './use-auth';
 
export function RequireAuth() {
  const { currentUser, isLoading } = useAuth();
  const navigate = useNavigate();
 
  useEffect(() => {
    if (!isLoading && !currentUser) {
      navigate('/auth/login');
    }
  }, [currentUser, isLoading, navigate]);
 
  return currentUser ? <Outlet /> : null;
}

Authentication Routes

Authentication routes are defined in src/auth/auth-routing.tsx:

// src/auth/auth-routing.tsx
import { lazy } from 'react';
import { Routes, Route, Navigate } from 'react-router-dom';
import { AuthLayout } from '@/layouts/auth/layout';
 
const LoginPage = lazy(() => import('@/pages/auth/login-page'));
const RegisterPage = lazy(() => import('@/pages/auth/register-page'));
const ForgotPasswordPage = lazy(() => import('@/pages/auth/forgot-password-page'));
 
export function AuthRouting() {
  return (
    <Routes>
      <Route element={<AuthLayout />}>
        <Route path="login" element={<LoginPage />} />
        <Route path="register" element={<RegisterPage />} />
        <Route path="forgot-password" element={<ForgotPasswordPage />} />
        <Route path="*" element={<Navigate to="/auth/login" />} />
      </Route>
    </Routes>
  );
}

Using Layouts

Layouts are used to provide a consistent UI structure for multiple routes. In Metronic React, layouts are implemented as route wrappers:

// src/layouts/demo3/layout.tsx
import { Outlet } from 'react-router-dom';
import { Header } from './components/header';
import { Sidebar } from './components/sidebar';
import { Footer } from './components/footer';
 
export function Demo3Layout() {
  return (
    <div className="layout">
      <Header />
      <div className="flex">
        <Sidebar />
        <main className="content">
          <Outlet />
        </main>
      </div>
      <Footer />
    </div>
  );
}

The Outlet component is where the matched route content will be rendered.

For navigation between routes, use the Link component from React Router:

import { Link } from 'react-router-dom';
 
// Basic link
<Link to="/dashboard">Dashboard</Link>
 
// Link with state
<Link
  to="/profile"
  state={{ from: 'dashboard' }}
>
  Profile
</Link>

Programmatic Navigation

For programmatic navigation (e.g., after form submission), use the useNavigate hook:

import { useNavigate } from 'react-router-dom';
 
function LoginForm() {
  const navigate = useNavigate();
 
  const handleLogin = async (formData) => {
    // Login logic...
    if (success) {
      navigate('/dashboard');
    }
  };
 
  // ...
}

Route Parameters

You can define dynamic routes with parameters:

// In app-routing-setup.tsx
<Route path="/profile/:id" element={<ProfilePage />} />
 
// In ProfilePage component
import { useParams } from 'react-router-dom';
 
function ProfilePage() {
  const { id } = useParams();
 
  // Use the id parameter
  return <div>Profile ID: {id}</div>;
}

Nested Routes

Nested routes allow you to organize related routes:

// In app-routing-setup.tsx
<Route path="/settings" element={<SettingsLayout />}>
  <Route index element={<GeneralSettings />} />
  <Route path="profile" element={<ProfileSettings />} />
  <Route path="security" element={<SecuritySettings />} />
</Route>
 
// In SettingsLayout component
import { Outlet } from 'react-router-dom';
 
function SettingsLayout() {
  return (
    <div className="settings-layout">
      <SettingsSidebar />
      <div className="settings-content">
        <Outlet />
      </div>
    </div>
  );
}

Route Meta Data

To associate meta data with routes, you can create a route configuration object:

// src/routing/routes.ts
export const routes = [
  {
    path: '/',
    element: <DefaultPage />,
    meta: {
      title: 'Dashboard',
      breadcrumb: 'Home'
    }
  },
  {
    path: '/profile',
    element: <ProfilePage />,
    meta: {
      title: 'User Profile',
      breadcrumb: 'Profile'
    }
  }
];

Then use this configuration to generate routes and access meta data:

// Example usage in a component
import { useLocation } from 'react-router-dom';
import { routes } from '@/routing/routes';
 
function PageTitle() {
  const location = useLocation();
  const route = routes.find(r => r.path === location.pathname);
  const title = route?.meta?.title || 'Metronic';
 
  return <h1>{title}</h1>;
}

Error Routes

Error routes are defined in src/errors/error-routing.tsx and handle various error states:

// src/errors/error-routing.tsx
import { lazy } from 'react';
import { Routes, Route, Navigate } from 'react-router-dom';
import { ErrorLayout } from '@/layouts/error/layout';
 
const Error404Page = lazy(() => import('@/pages/errors/error-404-page'));
const Error500Page = lazy(() => import('@/pages/errors/error-500-page'));
 
export function ErrorRouting() {
  return (
    <Routes>
      <Route element={<ErrorLayout />}>
        <Route path="404" element={<Error404Page />} />
        <Route path="500" element={<Error500Page />} />
        <Route path="*" element={<Navigate to="/error/404" />} />
      </Route>
    </Routes>
  );
}

Loading Indicator

Metronic React includes a top loading bar to show route navigation progress:

// Usage in app-routing.tsx
import TopBarProgress from 'react-top-loading-bar';
import { useProgress } from '@/hooks/use-progress';
 
const Routing = () => {
  const { progress } = useProgress();
 
  return (
    <>
      <TopBarProgress
        color='#4338ca'
        progress={progress}
      />
      {/* Routes */}
    </>
  );
};

For more details, see the source code in the src/routing directory.