Skip to content

Adding Pages

How to create new pages in the Apex Dashboard and integrate them into the sidebar navigation.

Overview

Adding a new page to the dashboard takes three steps: create the page file, add it to the navigation configuration, and optionally customize it. The page automatically inherits the dashboard layout (sidebar, header, and content shell) because it lives inside the (dashboard) route group.

Step 1: Create the Page File

Create a new directory and page.tsx file inside src/app/(dashboard)/:

// src/app/(dashboard)/reports/page.tsx

export default function ReportsPage() {
  return (
    <div className="space-y-6">
      <div>
        <h1 className="text-2xl font-bold tracking-tight">Reports</h1>
        <p className="text-sm text-muted-foreground">
          View and generate reports for your business.
        </p>
      </div>

      {/* Your page content goes here */}
    </div>
  );
}

This page will be accessible at /reports. The (dashboard) route group does not appear in the URL.

Step 2: Add to Navigation

Open src/lib/navigation.ts and add a new entry to the navigationItems array:

import {
  // ... existing imports
  FileBarChart,
} from "lucide-react";

export const navigationItems: NavItem[] = [
  // ... existing items
  {
    label: "Reports",
    href: "/reports",
    icon: FileBarChart,
    keywords: ["reports", "analytics", "export"],
    group: "main",
  },
];

The sidebar will automatically render the new link. You can add an optional badge property (e.g., badge: "New") to show a count or label next to the link.

Step 3: Customize (Optional)

The page inherits the full dashboard layout automatically. You can enhance it with any of the available components:

// src/app/(dashboard)/reports/page.tsx
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Download } from "lucide-react";

export default function ReportsPage() {
  return (
    <div className="space-y-6">
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-2xl font-bold tracking-tight">Reports</h1>
          <p className="text-sm text-muted-foreground">
            View and generate reports for your business.
          </p>
        </div>
        <Button>
          <Download className="size-4" />
          Export
        </Button>
      </div>

      <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
        <Card>
          <CardHeader>
            <CardTitle>Monthly Revenue</CardTitle>
          </CardHeader>
          <CardContent>
            <p className="text-sm text-muted-foreground">
              Revenue breakdown for the current month.
            </p>
          </CardContent>
        </Card>
        {/* More cards... */}
      </div>
    </div>
  );
}

Client vs. Server Components

By default, Next.js pages are server components. If your page needs interactivity (state, effects, event handlers), add the "use client" directive at the top of the file:

"use client";

import { useState } from "react";

export default function InteractivePage() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  );
}

For better performance, keep pages as server components when possible and extract interactive parts into smaller client components.

Nested Routes

To create nested pages (e.g., a detail view), add subdirectories:

src/app/(dashboard)/reports/
├── page.tsx                # /reports (list view)
├── [id]/
│   └── page.tsx            # /reports/123 (detail view)
└── create/
    └── page.tsx            # /reports/create (form)

Square brackets denote a dynamic segment. The params.id value is available as a prop in the page component.

Next Steps

Browse the Components page for a full list of available UI primitives, or learn about Theming to customize the dashboard's appearance.