Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to build a dashboard in React

Building a dashboard in React requires a layout with a sidebar and header, lazy-loaded routes for each section, and data visualization components that load data asynchronously. As the creator of CoreUI — an open-source UI framework used by over 500,000 developers — I designed the React dashboard template architecture that powers thousands of production admin panels. The key pattern is a layout wrapper component that renders the sidebar, header, and a content area with <Outlet />, combined with React Router’s lazy() for code splitting. This ensures the initial bundle is small and each dashboard section loads only when visited.

Install CoreUI React and React Router.

npm install @coreui/react @coreui/icons-react react-router-dom
// layouts/DefaultLayout.jsx
import { Suspense } from 'react'
import { Outlet } from 'react-router-dom'
import {
  CSidebar,
  CSidebarBrand,
  CSidebarNav,
  CNavItem,
  CNavTitle,
  CContainer
} from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { cilSpeedometer, cilPeople, cilChartLine, cilSettings } from '@coreui/icons'

const navItems = [
  { component: CNavTitle, name: 'Main' },
  { component: CNavItem, name: 'Dashboard', to: '/dashboard', icon: <CIcon icon={cilSpeedometer} /> },
  { component: CNavItem, name: 'Users', to: '/users', icon: <CIcon icon={cilPeople} /> },
  { component: CNavItem, name: 'Analytics', to: '/analytics', icon: <CIcon icon={cilChartLine} /> },
  { component: CNavItem, name: 'Settings', to: '/settings', icon: <CIcon icon={cilSettings} /> }
]

export function DefaultLayout() {
  return (
    <div>
      <CSidebar colorScheme="dark" position="fixed">
        <CSidebarBrand>My Dashboard</CSidebarBrand>
        <CSidebarNav>
          {navItems.map((item, i) => {
            const { component: Comp, name, to, icon } = item
            return to
              ? <CNavItem key={i} href={to}>{icon} {name}</CNavItem>
              : <CNavTitle key={i}>{name}</CNavTitle>
          })}
        </CSidebarNav>
      </CSidebar>

      <div className="wrapper d-flex flex-column min-vh-100 ms-sidebar">
        <div className="body flex-grow-1 p-3">
          <CContainer lg>
            <Suspense fallback={<div>Loading...</div>}>
              <Outlet />
            </Suspense>
          </CContainer>
        </div>
      </div>
    </div>
  )
}

Lazy-Loaded Routes

Code-split each dashboard section.

// App.jsx
import { lazy } from 'react'
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import { DefaultLayout } from './layouts/DefaultLayout'
import { ProtectedRoute } from './components/ProtectedRoute'

const Dashboard = lazy(() => import('./views/Dashboard'))
const Users = lazy(() => import('./views/Users'))
const Analytics = lazy(() => import('./views/Analytics'))
const Login = lazy(() => import('./views/Login'))

export default function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/login" element={<Login />} />
        <Route element={<ProtectedRoute />}>
          <Route element={<DefaultLayout />}>
            <Route path="/dashboard" element={<Dashboard />} />
            <Route path="/users" element={<Users />} />
            <Route path="/analytics" element={<Analytics />} />
            <Route path="/" element={<Navigate to="/dashboard" replace />} />
          </Route>
        </Route>
      </Routes>
    </BrowserRouter>
  )
}

lazy() creates code-split chunks for each section. The Suspense in DefaultLayout shows “Loading…” while the chunk downloads. ProtectedRoute wraps all authenticated routes.

Stats Cards Component

Display KPIs with CoreUI cards.

// views/Dashboard.jsx
import { CCard, CCardBody, CRow, CCol, CProgress } from '@coreui/react'

const stats = [
  { label: 'Users', value: '9,828', progress: 75, color: 'info' },
  { label: 'Revenue', value: '$6,200', progress: 60, color: 'success' },
  { label: 'Orders', value: '2,371', progress: 43, color: 'warning' },
  { label: 'Growth', value: '18%', progress: 18, color: 'primary' }
]

export default function Dashboard() {
  return (
    <CRow>
      {stats.map(stat => (
        <CCol key={stat.label} sm={6} xl={3}>
          <CCard className="mb-4">
            <CCardBody>
              <div className="fs-4 fw-semibold">{stat.value}</div>
              <div className="text-muted">{stat.label}</div>
              <CProgress className="mt-3" color={stat.color} value={stat.progress} />
            </CCardBody>
          </CCard>
        </CCol>
      ))}
    </CRow>
  )
}

Best Practice Note

This is the exact architecture used in CoreUI React Admin Template, which provides a complete production-ready starting point with authentication, routing, charts, and a full CoreUI component library wired together. For teams building enterprise dashboards, starting from the CoreUI template saves significant setup time. See how to integrate React with REST API to connect your dashboard to real-time data.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.

Answers by CoreUI Core Team