Getting started

Installation

Install shadcn-scheduler — own the full source, use the npm package, or pick individual modules.

Installation

shadcn-scheduler gives you three installation paths. The key difference is ownership and bundle size.

Install only what you need

Pick the preset that matches your use case. Each one copies only the files that domain actually needs — no bloat from views or engines you'll never use.

PresetUse caseViews includedInstall command
Full bundleEverythingAll viewsnpx shadcn@latest add https://shadcn-scheduler.vercel.app/registry.json
RosterWorkforce shift schedulingDay, Week, Month, Year, Listnpx shadcn@latest add https://shadcn-scheduler.vercel.app/r/scheduler-roster.json
TV / EPGTV guide, programme schedulingTimelinenpx shadcn@latest add https://shadcn-scheduler.vercel.app/r/scheduler-tv.json
ConferenceEvent & session schedulingDay, Week, Month, Listnpx shadcn@latest add https://shadcn-scheduler.vercel.app/r/scheduler-conference.json
FestivalMusic festival lineupsTimelinenpx shadcn@latest add https://shadcn-scheduler.vercel.app/r/scheduler-festival.json
HealthcareWard & staff rotasDay, Week, Month, Listnpx shadcn@latest add https://shadcn-scheduler.vercel.app/r/scheduler-healthcare.json
GanttProject & sprint planningWeek, Day, Listnpx shadcn@latest add https://shadcn-scheduler.vercel.app/r/scheduler-gantt.json
VenueRoom & space bookingsTimelinenpx shadcn@latest add https://shadcn-scheduler.vercel.app/r/scheduler-venue.json

What gets copied

Grid-based presets (Roster, Conference, Healthcare, Gantt) copy:

  • Core primitives — types.ts, constants.ts, context.tsx, config.ts
  • Grid engine — GridView.tsx, drag engine, geometry, day/week/month/year views
  • Domain config — the preset labels and defaults for your use case

Timeline-based presets (TV, Festival, Venue) copy:

  • Core primitives — same as above
  • Timeline engine — TimelineView.tsx (horizontal scroll, resources as rows)
  • Domain config — the preset labels and defaults for your use case

The full bundle copies all of the above plus every domain config.

Example — TV / EPG only

npx shadcn@latest add https://shadcn-scheduler.vercel.app/r/scheduler-tv.json

Copies ~32 files into components/scheduler/. You import from your own folder:

import { Scheduler, createSchedulerConfig } from '@/components/scheduler'

const config = createSchedulerConfig({ preset: 'tv', snapMinutes: 15 })

export default function EPGPage() {
  return (
    <div className="h-[600px]">
      <Scheduler
        categories={channels}
        employees={channelEmployees}
        shifts={programmes}
        onShiftsChange={setProgs}
        initialView="timeline"
        config={config}
      />
    </div>
  )
}

Example — Workforce Roster only

npx shadcn@latest add https://shadcn-scheduler.vercel.app/r/scheduler-roster.json
import { Scheduler, createSchedulerConfig } from '@/components/scheduler'

const config = createSchedulerConfig({ preset: 'roster', initialScrollToNow: true, snapMinutes: 30 })

Why this matters: You can edit GridView.tsx, add fields to types.ts, change the drag behaviour — anything you want. No fork, no patch file, no fighting a third-party package. And you only copy what you actually use.


Option 2 — npm package (all presets, single install)

If you prefer not to own the source, use the npm package:

npm install @sushill/shadcn-scheduler
import { Scheduler, createSchedulerConfig } from '@sushill/shadcn-scheduler'

// TV preset:
const tvConfig = createSchedulerConfig({ preset: 'tv' })
// Roster preset:
const rosterConfig = createSchedulerConfig({ preset: 'roster', initialScrollToNow: true })

Option 3 — Modular packages (tree-shakeable)

The @shadcn-scheduler/* monorepo lets you install only the packages you actually use. No dead code.

Install the foundation

npm install @shadcn-scheduler/core @shadcn-scheduler/shell

Add only the views you need

# Month calendar
npm install @shadcn-scheduler/view-month

# Year heatmap
npm install @shadcn-scheduler/view-year

# Tabular list view
npm install @shadcn-scheduler/view-list

# Grid views (day, week, timeline, kanban)
npm install @shadcn-scheduler/view-day @shadcn-scheduler/view-week
npm install @shadcn-scheduler/view-timeline @shadcn-scheduler/view-kanban

Add only the plugins you need

npm install @shadcn-scheduler/plugin-audit       # action history
npm install @shadcn-scheduler/plugin-recurrence  # recurring shifts
npm install @shadcn-scheduler/plugin-export      # CSV / ICS / PDF export
npm install @shadcn-scheduler/plugin-markers     # draggable deadline lines
npm install @shadcn-scheduler/plugin-dependencies  # SVG dependency arrows
npm install @shadcn-scheduler/plugin-histogram   # utilisation chart
npm install @shadcn-scheduler/plugin-availability  # availability overlays

Or use a domain preset config

npm install @shadcn-scheduler/preset-tv
npm install @shadcn-scheduler/preset-healthcare
npm install @shadcn-scheduler/preset-conference

Or install the fat bundle (same API as Option 2)

npm install @shadcn-scheduler/scheduler

Minimal usage example

'use client'
import { SchedulerProvider } from '@shadcn-scheduler/shell'
import { MonthView } from '@shadcn-scheduler/view-month'
import type { SchedulerConfig } from '@shadcn-scheduler/core'

const config: SchedulerConfig = { snapMinutes: 30 }

export default function App() {
  return (
    <SchedulerProvider categories={categories} employees={employees} config={config}>
      <MonthView date={new Date()} shifts={shifts} setShifts={setShifts} onAddShift={handleAdd} />
    </SchedulerProvider>
  )
}

→ Full modular packages reference | → Try the demo


Requirements

  • React 18+
  • Tailwind CSS 3 or 4
  • shadcn/ui CSS variables (or add them manually — see below)

Peer dependencies

Grid-based presets (Roster, Conference, Healthcare, Gantt) need:

npm install @tanstack/react-virtual react-resizable-panels @radix-ui/react-context-menu @radix-ui/react-popover @radix-ui/react-tabs @radix-ui/react-toggle-group @radix-ui/react-checkbox @radix-ui/react-slot lucide-react react-day-picker class-variance-authority clsx tailwind-merge

Timeline-based presets (TV, Festival, Venue) need a smaller set:

npm install @tanstack/react-virtual @radix-ui/react-popover @radix-ui/react-tabs @radix-ui/react-checkbox @radix-ui/react-slot lucide-react react-day-picker class-variance-authority clsx tailwind-merge

Tailwind configuration

Add the scheduler to your Tailwind content array:

// tailwind.config.ts
export default {
  content: [
    './app/**/*.{ts,tsx}',
    './components/**/*.{ts,tsx}',
    // If using npm package, also add:
    './node_modules/@sushill/shadcn-scheduler/dist/**/*.{js,mjs}',
  ],
}

CSS variables

The scheduler reads standard shadcn/ui CSS variables. If you're already on shadcn/ui — nothing extra needed.

If you're not on shadcn/ui, add these to your global CSS:

:root {
  --background: 0 0% 100%;
  --foreground: 240 10% 3.9%;
  --muted: 240 4.8% 95.9%;
  --muted-foreground: 240 3.7% 15.9%;
  --border: 240 5.9% 90%;
  --primary: 240 5.9% 10%;
  --primary-foreground: 0 0% 98%;
  --accent: 240 4.8% 95.9%;
  --accent-foreground: 240 5.9% 10%;
  --popover: 0 0% 100%;
  --popover-foreground: 240 10% 3.9%;
  --destructive: 0 84.2% 60.2%;
  --destructive-foreground: 0 0% 98%;
}
.dark {
  --background: 240 10% 3.9%;
  --foreground: 0 0% 98%;
  --muted: 240 3.7% 15.9%;
  --muted-foreground: 240 5% 64.9%;
  --border: 240 3.7% 15.9%;
  --primary: 0 0% 98%;
  --primary-foreground: 240 5.9% 10%;
  --accent: 240 3.7% 15.9%;
  --accent-foreground: 0 0% 98%;
  --popover: 240 10% 3.9%;
  --popover-foreground: 0 0% 98%;
  --destructive: 0 62.8% 30.6%;
  --destructive-foreground: 0 0% 98%;
}

Verify the install

import { Scheduler } from '@/components/scheduler'         // registry
// import { Scheduler } from '@sushill/shadcn-scheduler'   // npm Option 2
// import { Scheduler } from '@shadcn-scheduler/scheduler' // npm Option 3 fat bundle

export default function Test() {
  return (
    <div className="h-[500px]">
      <Scheduler
        categories={[{ id: 'c1', name: 'Team', kind: 'category', colorIdx: 0 }]}
        employees={[{ id: 'e1', name: 'Alex', kind: 'employee', categoryId: 'c1', colorIdx: 0 }]}
        shifts={[]}
        onShiftsChange={() => {}}
        initialView="week"
      />
    </div>
  )
}

If you see a weekly grid — you're set.

→ Open demo