Customization

Last updated on 2026-05-31

The Help Desk Kit is designed to be customized for your customer support platform or internal help desk tool. 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 theme uses oklch hue 280 (violet). Change the hue to rebrand the entire kit:

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

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

All 45 screens automatically inherit the new colors -- buttons, badges, links, charts, sidebar accents, priority indicators, SLA timers, status indicators, and focus rings all update at once.

Changing the Secondary Color

The secondary color uses a separate hue (default 91, golden-lime). To change it:

:root {
  /* Change from golden-lime (hue 91) to coral (hue 25) */
  --secondary: oklch(0.78 0.14 25);
  --secondary-foreground: oklch(0.25 0.05 25);
}

Changing Chart Colors

Update the five chart tokens to match your brand palette:

:root {
  --chart-1: oklch(0.55 0.2 220);   /* Primary chart color */
  --chart-2: oklch(0.75 0.14 25);   /* Secondary chart color */
  --chart-3: oklch(0.65 0.2 150);   /* Tertiary */
  --chart-4: oklch(0.6 0.18 300);   /* Quaternary */
  --chart-5: oklch(0.7 0.15 60);    /* Quinary */
}

All charts across dashboard, ticket analytics, reports, SLA tracking, and knowledge base analytics will update automatically.

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/ticket IDs respectively.

Replacing Seed Data

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

API calls

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

export default async function TicketsPage() {
  const tickets = await getTickets()
  return <TicketList data={tickets} />
}

Ticketing platform (Zendesk)

// app/api/zendesk/tickets/route.ts
export async function GET() {
  const res = await fetch("https://your-domain.zendesk.com/api/v2/tickets.json", {
    headers: {
      Authorization: `Basic ${btoa(`${process.env.ZENDESK_EMAIL}/token:${process.env.ZENDESK_API_TOKEN}`)}`,
    },
  })
  const data = await res.json()
  return Response.json(data.tickets.map((ticket: any) => ({
    id: `HD-${ticket.id}`,
    subject: ticket.subject,
    status: ticket.status,
    priority: ticket.priority,
    requester: ticket.requester_id,
    assignee: ticket.assignee_id,
    createdAt: ticket.created_at,
    updatedAt: ticket.updated_at,
  })))
}

Database (Prisma, Drizzle)

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

const tickets = await db.ticket.findMany({
  orderBy: { createdAt: "desc" },
  include: { requester: true, assignee: true, messages: true },
  take: 50,
})

CRM (HubSpot)

// app/api/hubspot/customers/route.ts
export async function GET() {
  const res = await fetch("https://api.hubapi.com/crm/v3/objects/contacts", {
    headers: { Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}` },
  })
  const data = await res.json()
  return Response.json(data.results)
}

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 Ticket
</Button>

Adding Component Variants

Components use class-variance-authority for variant management:

const priorityBadgeVariants = cva("...", {
  variants: {
    priority: {
      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",
      medium: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200",
      low: "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200",
    },
  },
})

Customizing the Sidebar

Edit components/layout/app-sidebar.tsx to add or remove navigation items. The sidebar reads from the navSections array in data/seed.ts:

export const dashboardNavItems: NavItem[] = [
  { label: "Dashboard", href: "/dashboard", icon: "LayoutDashboard" },
  { label: "Tickets", href: "/tickets", icon: "Ticket" },
  { label: "Customers", href: "/customers", icon: "Users" },
  // Remove items you don't need
  // Add items for new pages
]

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

Customizing the Header

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

  • Search -- global search across tickets, customers, and knowledge base
  • Notifications -- notification bell with unread count badge
  • 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 support workflow.

Adding New Pages

  1. Create a new route in app/(app)/your-page/page.tsx
  2. The page automatically inherits the app layout (sidebar, header)
  3. Add a sidebar link in data/seed.ts under the appropriate nav section
// app/(app)/escalations/page.tsx
export default function EscalationsPage() {
  return (
    <div className="space-y-6">
      <PageHeader
        title="Escalations"
        description="View and manage escalated tickets"
        breadcrumbs={[
          { label: "Dashboard", href: "/dashboard" },
          { label: "Escalations" },
        ]}
      />
      {/* Your content */}
    </div>
  )
}

Integrating Support Backends

Zendesk

// app/api/zendesk/tickets/route.ts
export async function GET() {
  const res = await fetch("https://your-domain.zendesk.com/api/v2/tickets.json", {
    headers: {
      Authorization: `Basic ${btoa(`${process.env.ZENDESK_EMAIL}/token:${process.env.ZENDESK_API_TOKEN}`)}`,
    },
  })
  const data = await res.json()
  return Response.json(data.tickets)
}

Freshdesk

// app/api/freshdesk/tickets/route.ts
export async function GET() {
  const res = await fetch("https://your-domain.freshdesk.com/api/v2/tickets", {
    headers: {
      Authorization: `Basic ${btoa(process.env.FRESHDESK_API_KEY + ":X")}`,
    },
  })
  const data = await res.json()
  return Response.json(data)
}

Intercom

// app/api/intercom/conversations/route.ts
export async function GET() {
  const res = await fetch("https://api.intercom.io/conversations", {
    headers: {
      Authorization: `Bearer ${process.env.INTERCOM_ACCESS_TOKEN}`,
      Accept: "application/json",
    },
  })
  const data = await res.json()
  return Response.json(data.conversations)
}

Integrating Chat Services

Pusher (real-time chat)

import Pusher from "pusher-js"

const pusher = new Pusher(process.env.NEXT_PUBLIC_PUSHER_KEY!, {
  cluster: process.env.NEXT_PUBLIC_PUSHER_CLUSTER!,
})

const channel = pusher.subscribe("chat-channel")
channel.bind("new-message", (data: ChatMessage) => {
  setMessages((prev) => [...prev, data])
})

Socket.IO

import { io } from "socket.io-client"

const socket = io(process.env.NEXT_PUBLIC_SOCKET_URL!)

socket.on("chat:message", (message: ChatMessage) => {
  setMessages((prev) => [...prev, message])
})

socket.emit("chat:send", { content: "Hello!", conversationId: "123" })

Removing Unused Features

Delete directories you don't need:

  • Don't need chat? Delete app/(app)/chat/ and components/chat/
  • Don't need knowledge base? Delete app/(app)/knowledge-base/ and components/knowledge-base/
  • Don't need automation? Delete app/(app)/automations/ and components/automations/
  • Don't need reports? Delete app/(app)/reports/ and components/reports/
  • Don't need team management? Delete app/(app)/team/ and components/team/
  • Run pnpm build to verify no broken imports
  • Remove corresponding sidebar items from data/seed.ts

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.