Skip to content

Data model

interface Resource {
id: string;
name: string;
role?: string; // shown under the name by the default header
events: SchedulerEvent[];
}
interface SchedulerEvent {
id: string;
title: string;
startDate: Date;
endDate: Date; // exclusive
color?: string; // any CSS color
description?: string;
}

By default an event lives in the events array of its resource. Moving an event to another row means taking it out of one array and putting it in another, which onEventDrop tells you to do.

If your data is a table of bookings, pass it as events and name the resource on each event instead. Then resources only needs id and name:

const people = [
{ id: "ann", name: "Ann" },
{ id: "bob", name: "Bob" },
];
const events = [
{ id: "1", title: "Standup", resourceId: "ann", startDate, endDate },
{ id: "2", title: "Kickoff", resourceIds: ["ann", "bob"], startDate, endDate }, // drawn in both rows
];
<ResourceScheduler resources={people} events={events} />

Both styles work together: flat events are added to whatever a resource holds in its own events. Events that name an unknown resource are not drawn. The handlers are unchanged and still give you fromResourceId and toResourceId, so a move is a setEvents(...) that changes the resourceId. For an event in resourceIds, swap fromResourceId for toResourceId in the list. Conflict rules see flat events too.

Event is still exported as a deprecated alias of SchedulerEvent. Prefer the new name: Event shadows the DOM global.

An event from 9:00 to 10:00 occupies 9:00 up to, but not including, 10:00. Another event starting at 10:00 does not overlap it. For all-day events, end at midnight of the next day: Monday to Wednesday inclusive is start = Mon 00:00, end = Thu 00:00, and the default card shows “All day”.

The scheduler does not copy resources. It reads the prop on every render, and when the user does something it calls a handler:

Handler When
onEventCreate(event, resourceId) A click or drag on empty slots, if you did not provide onSlotSelect
onSlotSelect({ resourceId, start, end }) The same gesture, handing you the range so you open your own dialog
onEventDrop(event, fromId, toId, start, end) An event was moved
onEventResize(event, resourceId, start, end) An event edge was dragged
onEventClick(event, resource) An event was clicked

Update your state in those and pass the new resources back. If you load data from a server, do the request in the handler and update state when it succeeds.

Only the events inside the visible range are drawn, so passing a whole year of events is fine for a week view.