Quick start
Here is the whole thing running live. Drag across empty days to create an event, drag an event to another day or person, click one.
The code
Section titled “The code”import { useState } from "react";import { ResourceScheduler, ViewType } from "resource-scheduler";import "resource-scheduler/dist/resource-scheduler.css";
export function Board() { const [resources, setResources] = useState([ { id: "ann", name: "Ann Lee", events: [ { id: "e1", title: "Standup", startDate: new Date(2026, 9, 12, 9), endDate: new Date(2026, 9, 12, 10), color: "#3b82f6", }, ], }, ]);
return ( <div style={{ height: 480 }}> <ResourceScheduler resources={resources} initialView={ViewType.Week} onEventCreate={(event, resourceId) => setResources((prev) => prev.map((r) => r.id === resourceId ? { ...r, events: [...r.events, { ...event, id: crypto.randomUUID() }] } : r ) ) } onEventDrop={(event, fromId, toId, start, end) => setResources((prev) => prev.map((r) => { const rest = r.events.filter((e) => e.id !== event.id); if (r.id === toId) return { ...r, events: [...rest, { ...event, startDate: start, endDate: end }] }; return r.id === fromId ? { ...r, events: rest } : r; }) ) } /> </div> );}Two things to notice:
- You own the state. The scheduler calls
onEventCreateandonEventDropand you updateresources. It never mutates what you pass in. - Handlers opt features in. Without
onEventDrop, a dropped event just snaps back. WithoutonEventResize, there are no resize handles.
Where next
Section titled “Where next”- Data model for the shapes of
resourcesand events. - Creating events to open your own dialog instead of auto-creating.
- Conflict control to stop double booking.