Customization

Last updated on 2026-08-26

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

Changing Colors

Update CSS custom properties in app/globals.css to change the palette across all 39 screens. The primary hue (30 = coral) is the most impactful change:

:root {
  /* Change 30 to your brand hue (0-360) */
  --primary: oklch(0.55 0.11 220);         /* Blue */
  --primary-foreground: oklch(0.98 0.005 220);
  --ring: oklch(0.55 0.11 220);
  --sidebar-primary: oklch(0.55 0.11 220);
  --sidebar-ring: oklch(0.55 0.11 220);
}

.dark {
  --primary: oklch(0.7 0.11 220);
  --primary-foreground: oklch(0.17 0.015 195);
  --ring: oklch(0.65 0.11 220);
  --sidebar-primary: oklch(0.7 0.11 220);
  --sidebar-ring: oklch(0.65 0.11 220);
}

All buttons, badges, focus rings, sidebar highlights, and chart colors automatically inherit the new palette.

Changing Typography

Configure fonts in app/layout.tsx:

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

const heading = DM_Sans({
  variable: "--font-figtree",
  subsets: ["latin"],
})

const body = Inter({
  variable: "--font-mulish",
  subsets: ["latin"],
})

const mono = JetBrains_Mono({
  variable: "--font-plex-mono",
  subsets: ["latin"],
  weight: ["400", "500"],
})

The CSS variable names stay the same (--font-figtree, --font-mulish, --font-plex-mono), so globals.css requires no changes.

Modifying Seed Data

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

// Before: static import
import { bookings, eventTypes } from "@/data/seed"

// After: fetch from your API
const bookings = await fetch("/api/bookings").then(r => r.json())
const eventTypes = await fetch("/api/event-types").then(r => r.json())

Seed data covers all domains:

Export Type Used By
bookings Booking[] Bookings dashboard, calendar, booking detail
eventTypes EventType[] Event types list, public booking, create booking dialog
contacts Contact[] Contacts list, contact detail
teamMembers TeamMember[] Team management, team availability
workflows Workflow[] Workflows list, workflow detail
dashboardStats DashboardStat[] KPI stat cards
bookingTrends BookingTrend[] Analytics charts
revenueTrends RevenueTrend[] Revenue analytics
calendarEvents CalendarEvent[] Calendar week view
weeklyHours WeeklyHours[] Availability editor
integrations Integration[] Settings integrations

Adding New Pages

Follow the existing pattern:

  1. Create a new page file in the appropriate route group:
# Admin page (gets sidebar layout)
app/(app)/reports/page.tsx

# Public page (minimal layout)
app/(public)/embed/page.tsx
  1. Import shared components and data:
"use client"

import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { bookings } from "@/data/seed"
import { formatDate } from "@/lib/format"

export default function ReportsPage() {
  return (
    <div className="space-y-6">
      <h1 className="font-heading text-2xl font-bold tracking-tight">Reports</h1>
      {/* Your content */}
    </div>
  )
}
  1. Add the route to the sidebar navigation in components/layout/app-sidebar.tsx.

Connecting a Real Backend

The Booking Kit is frontend-only. To connect a backend:

Calendar Provider

Wire the calendar view, availability, and booking data to your provider:

// Google Calendar API
const events = await calendar.events.list({
  calendarId: "primary",
  timeMin: startOfWeek.toISOString(),
  timeMax: endOfWeek.toISOString(),
})

// Or Cal.com API
const bookings = await fetch("https://api.cal.com/v1/bookings", {
  headers: { Authorization: `Bearer ${apiKey}` },
}).then(r => r.json())

Payment Processing

The payment screen (/book/payment) renders a card input UI. Connect your payment provider:

// Stripe
import { loadStripe } from "@stripe/stripe-js"
const stripe = await loadStripe(publishableKey)

// Create a payment intent on your backend
const { clientSecret } = await fetch("/api/create-payment-intent", {
  method: "POST",
  body: JSON.stringify({ amount, eventTypeId }),
}).then(r => r.json())

Authentication

Auth pages (/login, /register, /forgot-password) provide the UI. Connect your auth provider:

// NextAuth.js
import { signIn } from "next-auth/react"
await signIn("credentials", { email, password })

// Clerk
import { useSignIn } from "@clerk/nextjs"
const { signIn } = useSignIn()

// Supabase Auth
import { createClient } from "@supabase/supabase-js"
const { data } = await supabase.auth.signInWithPassword({ email, password })

Extending Components

Use the cn() utility to add custom classes to existing components:

import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"

<Button className={cn("rounded-full shadow-lg")} variant="default">
  Book Now
</Button>

Creating New Composites

Follow the component hierarchy:

  1. Place the file in the appropriate domain folder (components/booking/, components/dashboard/, etc.)
  2. Import primitives from components/ui/
  3. Accept typed props
  4. Export a named component
// components/booking/booking-reminder.tsx
import { Card, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import type { Booking } from "@/types"

interface BookingReminderProps {
  booking: Booking
  onDismiss: () => void
}

export function BookingReminder({ booking, onDismiss }: BookingReminderProps) {
  return (
    <Card>
      <CardContent className="p-4">
        <p className="text-sm font-medium">{booking.attendeeName}</p>
        <Button variant="ghost" size="sm" onClick={onDismiss}>Dismiss</Button>
      </CardContent>
    </Card>
  )
}

Adjusting the Radius

Change the base radius in globals.css to make the UI sharper or rounder:

:root {
  --radius: 0.5rem;    /* Sharp: 8px */
  --radius: 0.875rem;  /* Default: 14px */
  --radius: 1.25rem;   /* Rounded: 20px */
}

All computed radius scales (--radius-sm through --radius-4xl) adjust proportionally.

Next Steps