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:
- 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
- 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>
)
}
- 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:
- Place the file in the appropriate domain folder (
components/booking/,components/dashboard/, etc.) - Import primitives from
components/ui/ - Accept typed props
- 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
- Design Tokens -- full token reference
- Components -- component catalog with props
- Accessibility -- maintain accessibility when customizing