Customization

Last updated on 2026-03-26

The Kanban PM Kit is designed to be customized for your team or PM product. All components use design tokens and Tailwind CSS utilities, making brand adaptation straightforward.

Changing Colors

Update CSS custom properties in app/globals.css. The default blue-violet theme uses oklch hue 255. Change the hue to rebrand the entire kit:

:root {
  /* Change from blue-violet (hue 255) to teal (hue 180) */
  --primary: oklch(0.45 0.2 180);
  --primary-foreground: oklch(0.98 0 0);
  --accent: oklch(0.94 0.02 180);
  --accent-foreground: oklch(0.35 0.15 180);
  --ring: oklch(0.55 0.18 180);
}

.dark {
  --primary: oklch(0.7 0.18 180);
  --primary-foreground: oklch(0.15 0.02 180);
}

All 45+ screens automatically inherit the new colors -- buttons, badges, links, charts, sidebar accents, Kanban column indicators, and focus rings all update at once.

Changing Typography

Configure fonts in app/layout.tsx:

import { Inter, DM_Sans, JetBrains_Mono } from "next/font/google";

const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
const dmSans = DM_Sans({ subsets: ["latin"], variable: "--font-dm-sans" });
const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"], variable: "--font-jetbrains" });

Swap these for any Google Font or local font files. The CSS variables --font-sans, --font-heading, and --font-mono control body text, headings, and code respectively.

Replacing Seed Data

All mock data lives in data/seed.ts. Replace it with your data source:

API calls

import { getTasks } from "@/lib/api"

export default async function BoardPage() {
  const tasks = await getTasks(projectId)
  return <KanbanBoard tasks={tasks} />
}

Database (Prisma, Drizzle)

import { db } from "@/lib/db"

const tasks = await db.task.findMany({
  where: { projectId },
  orderBy: { updatedAt: "desc" },
  include: { subtasks: true, comments: true },
})

Project Management API (Linear, Jira)

// app/api/linear/issues/route.ts
export async function GET() {
  const res = await fetch("https://api.linear.app/graphql", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: process.env.LINEAR_API_KEY!,
    },
    body: JSON.stringify({
      query: `{ issues { nodes { id title state { name } priority assignee { name } } } }`,
    }),
  })
  const data = await res.json()
  return Response.json(data.data.issues.nodes)
}

Extending Components

Use the cn() utility (from lib/utils.ts) to add custom classes without conflicts:

import { Button } from "@/components/ui/button"

<Button className="rounded-full shadow-lg" size="lg">
  Create Task
</Button>

Adding Component Variants

Components use class-variance-authority for variant management:

const badgeVariants = cva("...", {
  variants: {
    variant: {
      default: "...",
      urgent: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200",
      high: "bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200",
    },
  },
})

Customizing the Sidebar

Edit components/layout/app-sidebar.tsx to add or remove navigation items:

const navItems = [
  { label: "Dashboard", href: "/", icon: LayoutDashboard },
  { label: "My Work", href: "/my-work", icon: User },
  { label: "Projects", href: "/projects", icon: FolderKanban },
  { label: "Activity", href: "/activity", icon: Activity },
  { label: "Inbox", href: "/inbox", icon: Inbox },
  { label: "Goals", href: "/goals", icon: Target },
  { label: "Roadmap", href: "/roadmap", icon: Map },
  { label: "Workload", href: "/workload", icon: BarChart3 },
  { label: "Analytics", href: "/analytics", icon: LineChart },
  { label: "Views", href: "/views", icon: Eye },
  { label: "Templates", href: "/templates", icon: LayoutTemplate },
  { label: "Team", href: "/team", icon: Users },
  // Remove items you don't need
  // Add items for new PM pages
]

Each item takes a label, href, and a Lucide icon component. Active state highlighting is handled automatically based on the current pathname.

Customizing the Header

Edit components/layout/app-header.tsx to modify quick actions in the top bar:

  • Command palette trigger -- the search input that opens Cmd+K
  • Notification bell -- links to the inbox/notifications page
  • Theme toggle -- switches between light and dark mode
  • User menu -- dropdown with profile, settings, and sign out

Remove or reorder these actions to fit your PM workflow.

Adding New Dashboard Pages

  1. Create a new route in app/(dashboard)/your-page/page.tsx
  2. The page automatically inherits the dashboard layout (sidebar, header)
  3. Add a sidebar link in components/layout/app-sidebar.tsx
// app/(dashboard)/retrospectives/page.tsx
export default function RetrospectivesPage() {
  return (
    <div className="space-y-6">
      <h1 className="font-heading text-2xl font-bold">Retrospectives</h1>
      {/* Your content */}
    </div>
  )
}

Customizing Task Statuses

The default statuses are Backlog, Todo, In Progress, In Review, Done, and Cancelled. To modify:

  1. Update the TaskStatusType union in types/index.ts
  2. Update the taskStatuses array in data/seed.ts with new status objects
  3. Update the StatusSelect component in components/pm/status-select.tsx
  4. Update the Kanban board columns in components/kanban/kanban-board.tsx
// types/index.ts
export type TaskStatusType =
  | "Backlog"
  | "Todo"
  | "In Progress"
  | "In Review"
  | "QA"           // Added
  | "Done"
  | "Cancelled"

Customizing Priority Levels

The default priorities are Urgent, High, Medium, Low, and None. To modify:

  1. Update the TaskPriorityLevel union in types/index.ts
  2. Update the PrioritySelect component colors and icons in components/pm/priority-select.tsx

Integrating PM Backends

Supabase

import { createClient } from "@supabase/supabase-js"

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)

const { data: tasks } = await supabase
  .from("tasks")
  .select("*, subtasks(*), comments(*)")
  .eq("project_id", projectId)
  .order("created_at", { ascending: false })

Firebase Firestore

import { collection, query, where, orderBy, getDocs } from "firebase/firestore"
import { db } from "@/lib/firebase"

const tasksQuery = query(
  collection(db, "tasks"),
  where("projectId", "==", projectId),
  orderBy("updatedAt", "desc")
)
const snapshot = await getDocs(tasksQuery)
const tasks = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }))

Convex

import { useQuery } from "convex/react"
import { api } from "@/convex/_generated/api"

const tasks = useQuery(api.tasks.listByProject, { projectId })

Removing Unused Features

Delete directories you don't need:

  • Don't need cycles? Delete app/(dashboard)/projects/[id]/cycles/ and components/pm/cycle-card.tsx
  • Don't need modules? Delete app/(dashboard)/projects/[id]/modules/ and components/pm/module-card.tsx
  • Don't need pages/wiki? Delete app/(dashboard)/projects/[id]/pages/
  • Don't need goals? Delete app/(dashboard)/goals/ and components/pm/goal-card.tsx
  • Don't need roadmap? Delete app/(dashboard)/roadmap/
  • Don't need automations? Delete app/(dashboard)/projects/[id]/automations/ and components/pm/automation-rule-card.tsx
  • Don't need timeline? Delete app/(dashboard)/projects/[id]/timeline/ and components/timeline/
  • Don't need analytics? Delete app/(dashboard)/analytics/, app/(dashboard)/projects/[id]/analytics/, and components/charts/
  • Run pnpm build to verify no broken imports

Using shadcn/ui CLI

Add new components alongside the kit:

npx shadcn@latest add <component-name>

Components install to components/ui/ and integrate seamlessly with the existing design tokens. The kit uses the new-york style with CSS variables enabled.