Scheduler · calendar & timeline

A planning calendar: month, week and day grids and a resource timeline — drag to move, pull an edge to resize, drag on empty space to create, overlapping events side by side, a now line, business hours, and keyboard moves.

Sep 21 – Sep 27, 2026

all-day
Offsite
On call
Tree view polish
1 AM
2 AM
3 AM
4 AM
5 AM
6 AM
7 AM
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
6 PM
7 PM
8 PM
9 PM
10 PM
11 PM
Sprint planning10:00 AM – 11:30 AM
1:1 Grace / Ada9:30 AM – 10:00 AM
Pairing: kanban keyboard12:00 PM – 2:00 PM
Lunch & learn: signals12:30 PM – 1:30 PM
Design review2:00 PM – 3:00 PM
Deploy window4:00 PM – 6:00 PM
Customer call11:00 AM – 11:45 AM
Retro4:00 PM – 5:00 PM

Drag an event, pull its edge, or drag on empty space.

Keys on a focused event: Enter opens · Alt + ← → a day · Alt + ↑ ↓ a slot (a row in the timeline) · Alt + Shift + arrows its length · Delete removes it.

Usage

JavaScript
import { signal } from "./index.js";import { Scheduler } from "./components/scheduler.js"; const events = signal([{ id: 1, title: "Design review", start: new Date(2026, 8, 24, 14), end: new Date(2026, 8, 24, 15), resourceId: "ada" }]);Scheduler({  events,                                    // rewritten on every move / resize  view: "week",                              // "month" | "week" | "day" | "timeline"  resources: [{ id: "ada", name: "Ada Lovelace", hue: 262 },],   // timeline rows (a workload view)  onEventChange: (ev, next) => api.save(ev.id, next),              // false / a rejected promise puts it back  onCreate: ({ start, end, allDay, resourceId }) => ({ id: crypto.randomUUID(), title: "New", start, end, allDay, resourceId }),  onEventClick: (ev) => open(ev),  slotMinutes: 30, businessHours: { start: 9, end: 18 }, timelineDays: 14,})