Scheduler
A time-based multi-resource scheduler with drag-and-drop, resize, snapping, collision detection, and custom rendering. Zero external dependencies.
Overview
Introduction
TimelineScheduler renders resources as rows and events as positioned blocks on a time axis. It handles all pointer interactions internally — drag-and-drop, resize, click-to-create — and fires callbacks so your app stays in control of the data. Toggle the options below to explore all props.
Setup
Getting started
Install the package from npm:
npm install @widgetkit/scheduler-react
# or
pnpm add @widgetkit/scheduler-reactImport the component and its stylesheet:
import { TimelineScheduler } from "@widgetkit/scheduler-react";
import "@widgetkit/scheduler-react/styles.css";Pass resources, items, and date — those are the only required props. Enable interactions with boolean flags:
import { useState } from "react";
import { TimelineScheduler } from "@widgetkit/scheduler-react";
import "@widgetkit/scheduler-react/styles.css";
import type { Resource, TimelineItem } from "@widgetkit/scheduler-react";
const resources: Resource[] = [
{ id: "alice", name: "Alice Hansen" },
{ id: "bob", name: "Bob Nilsen" },
];
const initialItems: TimelineItem[] = [
{
id: "1",
resourceId: "alice",
name: "Team standup",
color: "#6c63ff",
start: new Date("2024-06-10T09:00"),
end: new Date("2024-06-10T09:30"),
},
];
export function App() {
const [items, setItems] = useState(initialItems);
const [date, setDate] = useState(new Date());
return (
<TimelineScheduler
resources={resources}
items={items}
date={date}
startHour={8}
endHour={20}
draggable
resizable
creatable
showDateNav
showZoomControls
showNowLine
showTooltip
onItemsChange={setItems}
onDateChange={setDate}
/>
);
}Example
Drag & drop
Enable draggable to move events across resources and time. resizable adds handles on both edges. creatable lets users draw new events by clicking and holding on empty space. All interactions snap to snapMinutes (default 15).
Callbacks like onItemDragEnd, onItemResizeEnd, and onItemCreate fire with the updated position so you can persist changes to your backend.
<TimelineScheduler
resources={resources}
items={items}
date={date}
draggable
resizable
creatable
snapMinutes={15}
startHour={8}
endHour={18}
showDateNav
showZoomControls
showNowLine
showTooltip
onItemsChange={setItems}
onDateChange={setDate}
onItemDragEnd={({ item }) =>
console.log(`Moved "${item.name}" to ${item.start.toLocaleTimeString()}`)
}
onItemResizeEnd={({ item }) =>
console.log(`Resized "${item.name}": ${item.start} – ${item.end}`)
}
onItemCreate={({ resourceId, start }) =>
console.log(`New event for ${resourceId} at ${start}`)
}
/>Example
Custom rendering
The renderItem prop replaces the default event card with whatever React you return. The full TimelineItem object is passed in, including the optional description field — useful for showing notes, metadata, or custom badges inside events.
function renderItem(item: TimelineItem) {
return (
<div style={{ display: "flex", height: "100%", overflow: "hidden" }}>
<div
style={{ width: 3, flexShrink: 0, background: item.color }}
/>
<div style={{ padding: "3px 6px", overflow: "hidden" }}>
<div style={{ fontWeight: 600, fontSize: 12, whiteSpace: "nowrap",
overflow: "hidden", textOverflow: "ellipsis" }}>
{item.name}
</div>
{item.description && (
<div style={{ fontSize: 11, opacity: 0.7, whiteSpace: "nowrap",
overflow: "hidden", textOverflow: "ellipsis" }}>
{item.description}
</div>
)}
</div>
</div>
);
}
<TimelineScheduler
resources={resources}
items={items}
date={date}
renderItem={renderItem}
draggable
resizable
startHour={8}
endHour={18}
onItemsChange={setItems}
onDateChange={setDate}
/>Example
Read only
Pass readonly to disable all interactions. The scheduler becomes a pure display component — useful for dashboards, public calendars, or embedding in contexts where editing isn't appropriate. Combine with showAvatar to show resource photos alongside their rows.
const resources: Resource[] = [
{ id: "r1", name: "Alice Hansen", avatar: "https://..." },
{ id: "r2", name: "Bob Nilsen", avatar: "https://..." },
];
<TimelineScheduler
resources={resources}
items={items}
date={date}
readonly
showDateNav
showZoomControls
showAvatar
showNowLine
showTooltip
startHour={8}
endHour={18}
onDateChange={setDate}
/>Reference
Props
All props except resources, items, and date are optional. Props marked * are required.
| Prop | Type | Default | Description |
|---|---|---|---|
| Data | |||
resources* | Resource[] | — | Array of resources rendered as rows |
items* | TimelineItem[] | — | Array of events to display |
date* | Date | — | Currently displayed date |
| Time range | |||
startHour | number | 0 | First visible hour (0–23) |
endHour | number | 24 | Last visible hour (1–24) |
snapMinutes | number | 15 | Snap interval for drag and create interactions |
| Interaction | |||
draggable | boolean | true | Allow moving events to a new time or resource |
resizable | boolean | false | Allow resizing events by dragging their edges |
creatable | boolean | false | Allow creating events by clicking and dragging on empty space |
editable | boolean | true | Allow editing events via the built-in modal |
readonly | boolean | false | Disable all interactions — overrides draggable, resizable, creatable, editable |
minDurationMinutes | number | 0 | Minimum event duration in minutes (0 = no limit) |
maxDurationMinutes | number | 0 | Maximum event duration in minutes (0 = no limit) |
| Display | |||
zoom | 1 | 2 | 4 | 1 | Horizontal zoom level |
showNav | boolean | false | Show the built-in navigation bar |
showDateNav | boolean | true | Show previous / next day arrows |
showZoomControls | boolean | true | Show zoom level buttons |
showTime | boolean | true | Show time label inside events |
showAvatar | boolean | true | Show resource avatar in the row header |
showEventCount | boolean | true | Show count badge when events overlap |
showTooltip | boolean | true | Show hover tooltip with event details |
showNowLine | boolean | true | Show live indicator for the current time |
| Custom rendering | |||
renderItem | (item: TimelineItem) => ReactNode | — | Replaces the default event card with custom content |
| Callbacks | |||
onItemsChange | (items: TimelineItem[]) => void | — | Full updated items array after any change |
onDateChange | (date: Date) => void | — | Displayed date changed |
onZoomChange | (zoom: 1 | 2 | 4) => void | — | Zoom level changed |
onItemCreate | (detail: ItemCreateDetail) => void | — | New event drawn by the user |
onItemClick | (detail: ItemClickDetail) => void | — | Event single-clicked |
onItemDblClick | (detail: ItemDblClickDetail) => void | — | Event double-clicked |
onItemHover | (detail: ItemHoverDetail) => void | — | Mouse entered or left an event |
onItemContextMenu | (detail: ItemContextMenuDetail) => void | — | Event right-clicked |
onItemDragStart | (detail: ItemDragStartDetail) => void | — | Drag interaction began |
onItemDragEnd | (detail: ItemDragEndDetail) => void | — | Drag ended with new resourceId, start, end |
onItemResizeStart | (detail: ItemResizeStartDetail) => void | — | Resize interaction began |
onItemResizeEnd | (detail: ItemResizeEndDetail) => void | — | Resize ended with new start and end |
Reference
TypeScript types
All types are exported from both @widgetkit/scheduler-react and @widgetkit/scheduler-vue.
import type {
Resource,
TimelineItem,
ItemCreateDetail,
ItemClickDetail,
ItemDblClickDetail,
ItemHoverDetail,
ItemContextMenuDetail,
ItemDragStartDetail,
ItemDragEndDetail,
ItemResizeStartDetail,
ItemResizeEndDetail,
} from "@widgetkit/scheduler-react";// Core data types
interface Resource {
id: string;
name: string;
avatar?: string;
}
interface TimelineItem {
id: string;
resourceId: string;
name: string;
color: string;
start: Date;
end: Date;
description?: string;
}
// Callback detail types
interface ItemCreateDetail { resourceId: string; start: Date; end: Date }
interface ItemClickDetail { item: TimelineItem }
interface ItemDblClickDetail { item: TimelineItem }
interface ItemHoverDetail { item: TimelineItem; type: "enter" | "leave" }
interface ItemContextMenuDetail { item: TimelineItem; x: number; y: number }
interface ItemDragStartDetail { item: TimelineItem }
interface ItemDragEndDetail { item: TimelineItem; resourceId: string; start: Date; end: Date }
interface ItemResizeStartDetail { item: TimelineItem }
interface ItemResizeEndDetail { item: TimelineItem; start: Date; end: Date }Reference
Keyboard shortcuts
When an event is selected, the following keyboard shortcuts are available. Interactions respect readonly — shortcuts are disabled when it is set.