Next.js/Shadcn Calendar with Multiple Views & Event Management

Production-ready React Event Calendar with Next.js support. Multiple views, event management, TypeScript, and responsive design.

Shadcn Event Calendar is a lightweight and customizable UI component for React & Next.js applications.

It helps you manage and display custom events with a responsive calendar UI across multiple views, including day, week, month, and year.

Features

📅 Multiple calendar views (day, week, month, agenda)

✏️ Full event CRUD operations (create, read, update, delete)

🔄 Recurring events with daily, weekly, and monthly patterns

🎨 Customizable event categories and color coding

🎪 Smooth animations powered by Framer Motion

🌙 Theme support with dark/light mode options

🔗 URL-based state management with nuqs

🗃️ Type-safe database operations with Drizzle ORM

Preview

shadcn-event-calendar

Use Cases

  • Corporate event management systems where teams need to schedule meetings, track deadlines, and coordinate project timelines across different departments
  • Educational platforms requiring class scheduling, assignment due dates, exam calendars, and academic event coordination for students and faculty
  • Healthcare applications managing patient appointments, doctor schedules, medical facility bookings, and recurring treatment sessions
  • Event booking platforms for venues, conferences, workshops, or services where customers need to view availability and book time slots
  • Personal productivity apps helping users organize their daily schedules, set reminders, track habits, and manage both work and personal commitments

How to Use It

1. Install Shadcn Event Calendar using your preferred package manager:

# npm
npx shadcn@VERSION add "https://shadcn-event-calendar.vercel.app/r/event-calendar.json"
# yarn
yarn add shadcn@VERSION "https://shadcn-event-calendar.vercel.app/r/event-calendar.json"
# pnpm
pnpm add shadcn@VERSION "https://shadcn-event-calendar.vercel.app/r/event-calendar.json"
# bun
bun add shadcn@VERSION "https://shadcn-event-calendar.vercel.app/r/event-calendar.json"

2. Wrap your root layout with the NuqsAdapter for state management and add the Toaster for notifications.

// app/layout.tsx
import { ThemeProvider } from '@/components/theme-provider';
import { Toaster } from 'sonner';
import { NuqsAdapter } from '@/components/event-calendar/nuqs-adapter';
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        >
          <Toaster expand={true} richColors position="top-center" />
          <NuqsAdapter>{children}</NuqsAdapter>
        </ThemeProvider>
      </body>
    </html>
  );
}

3. You can now use the EventCalendar component in your application. The example below shows how to use it on a page with sample data.

// app/page.tsx
import { EventCalendar } from "@/components/event-calendar/event-calendar";
import { SearchParams } from "nuqs";
import { searchParamsCache } from "@/lib/searchParams";
import { Suspense } from "react";
import { Events } from "@/types/event";
const dummyEvents: Events[] = [
  {
    id: "1",
    title: "Daily Team Standup",
    description: "Daily sync to discuss progress and blockers.",
    startDate: new Date(),
    endDate: new Date(),
    startTime: "09:00",
    endTime: "09:30",
    isRepeating: true,
    repeatingType: "daily",
    location: "Virtual - Google Meet",
    category: "Work",
    color: "red",
    createdAt: new Date(),
    updatedAt: new Date(),
  },
  {
    id: "2",
    title: "Project Alpha Deadline",
    description: "Final submission for Project Alpha.",
    startDate: new Date(new Date().setDate(new Date().getDate() + 2)),
    endDate: new Date(new Date().setDate(new Date().getDate() + 2)),
    startTime: "17:00",
    endTime: "17:30",
    isRepeating: false,
    repeatingType: null,
    location: "Project Management Platform",
    category: "Project",
    color: "blue",
    createdAt: new Date(),
    updatedAt: new Date(),
  },
];
interface DemoPageProps {
  searchParams: Promise<SearchParams>;
}
export default async function Page(props: DemoPageProps) {
  const searchParams = await props.searchParams;
  const search = searchParamsCache.parse(searchParams);
  const eventsResponse = {
    events: dummyEvents,
  };
  return (
    <div className="flex min-h-screen flex-col">
      <main className="flex-1 py-6">
        <div className="container">
          <div className="bg-card overflow-hidden rounded-xl border shadow-sm">
            <Suspense
              fallback={
                <div className="flex h-[700px] items-center justify-center">
                  <div className="flex flex-col items-center gap-2">
                    <div className="border-primary h-8 w-8 animate-spin rounded-full border-4 border-t-transparent"></div>
                    <p className="text-muted-foreground text-sm">
                      Loading calendar...
                    </p>
                  </div>
                </div>
              }
            >
              <EventCalendar
                events={eventsResponse.events}
                initialDate={search.date}
              />
            </Suspense>
          </div>
        </div>
      </main>
    </div>
  );
}

Related Resources

  • Next.js: The React framework used for building the calendar. Official documentation provides in-depth guides and API references. https://nextjs.org/docs
  • shadcn/ui: The component library used for the UI. Explore the available components and customization options. https://ui.shadcn.com/
  • Tailwind CSS: The utility-first CSS framework for styling. The documentation is a reference for all utility classes. https://tailwindcss.com/docs
  • Drizzle ORM: The TypeScript ORM for database interactions. Learn how to define schemas and perform queries. https://orm.drizzle.team/

FAQs

Q: Is this calendar component compatible with both server and client components?
A: Yes, the calendar works with the Next.js App Router and supports both server and client components. It uses server-side rendering for the initial load and hydrates on the client for interactivity.

Q: How does state management work in this calendar?
A: The calendar uses Zustand for efficient client-side state management and nuqs to maintain the calendar’s state in the URL. This combination simplifies sharing specific views and dates.

Q: How does the data layer work with Drizzle ORM?
A: Event data is managed through Drizzle ORM for type-safe database operations. You can customize the event schema to fit your needs while maintaining type safety.

Fahreza Hidayat

Fahreza Hidayat

Leave a Reply

Your email address will not be published. Required fields are marked *