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.
all-day
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
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,})