Date & time
Scheduler
A week-view calendar grid with automatic overlap layout, drag-to-move, drag-to-resize, and full keyboard equivalents — for booking systems, shift schedules, and meeting planners.
SchedulerPreview
Jul 27 – Aug 2, 2026
Mon27
Tue28
Wed29
Thu30
Fri31
Sat1
Sun2
All day
8 AM9 AM10 AM11 AM12 PM1 PM2 PM3 PM4 PM5 PM6 PM7 PM
Usage
tsx
import { useState } from "react";
import { Scheduler, type SchedulerEvent } from "@vesture/react";
function Example() {
const [date, setDate] = useState(new Date());
const [events, setEvents] = useState<SchedulerEvent[]>([
{ id: "1", title: "Standup", start: nineAM, end: nineThirtyAM },
{ id: "2", title: "Design review", start: elevenAM, end: noon },
]);
return (
<Scheduler
date={date}
onDateChange={setDate}
events={events}
editable
startHour={8}
endHour={19}
onEventChange={(event, newStart, newEnd) =>
setEvents((prev) =>
prev.map((e) =>
e.id === event.id ? { ...e, start: newStart, end: newEnd } : e
)
)
}
/>
);
}Behavior
- Fully controlled: events and date are yours to own. Scheduler never mutates events, even while dragging — onEventChange reports the proposed new start/end and you decide whether to accept it, same philosophy as every other component here.
- Overlapping events in the same day cluster and pack into side-by-side columns automatically (a bridging event can link two events that don't directly overlap into one cluster) — no layout props to configure.
- startHour/endHour restrict the visible time range (default the full day, 0-24); slotDuration controls gridline density and is also the snap increment for drag/resize/keyboard moves.
- Events with allDay: true render in a separate row above the time grid and are never draggable or resizable.
- editable turns on drag-to-move (drag anywhere on an event body) and drag-to-resize (drag its bottom edge), both via Pointer Events, so they work uniformly with mouse, touch, and pen.
- Keyboard equivalents, always available when editable: ArrowUp/ArrowDown move a focused event by one slotDuration, ArrowLeft/ArrowRight move it to the adjacent day, Shift+ArrowUp/ArrowDown resizes its end time. Each keypress fires onEventChange immediately and is announced through an aria-live region for screen readers.
- minEventDuration (defaults to slotDuration) is the floor a resize can shrink an event's duration to.
- A dragged event's original slot dims in place while a preview block — showing the live would-be start/end time — follows the pointer; a resize instead live-updates the event's own height and end-time label directly.
Props
SchedulerEvent
| Prop | Type | Default | Description |
|---|---|---|---|
| id | string | — | Required. Must be stable across renders — used for overlap layout, drag tracking, and color hashing. |
| title | string | — | Required. Shown on the event block. |
| start / end | Date | — | Required. |
| allDay | boolean | — | Renders in the all-day row instead of the time grid; never draggable. |
| color | string | — | Overrides the auto-assigned color (hashed from id into the theme's chart.series1-8 tokens, so the same event always gets the same color). |
| data | unknown | — | Passthrough slot for your own metadata — Scheduler never reads it. |
Scheduler
| Prop | Type | Default | Description |
|---|---|---|---|
| events | SchedulerEvent[] | — | Required. |
| date / onDateChange | Date / (date: Date) => void | — | Any date within the displayed week; the prev/next/Today controls call onDateChange. |
| weekStartsOn | 0 | 1 | 1 | Sunday or Monday. |
| startHour / endHour | number | 0 / 24 | Visible time range. |
| slotDuration | number | 30 | Gridline density in minutes; also the drag/resize/keyboard snap increment. |
| onEventClick | (event: SchedulerEvent) => void | — | Fires on a plain click (or Enter/Space) — not fired for a click that ends a drag. |
| onEventChange | (event, newStart: Date, newEnd: Date) => void | — | Fires on drag-move drop, resize-release, or a keyboard move/resize. Scheduler doesn't mutate events — apply the change to your own state. |
| editable | boolean | false | Enables drag-to-move, drag-to-resize, and their keyboard equivalents on timed events. |
| minEventDuration | number | slotDuration | Minimum minutes a resize can shrink an event to. |
| selectedEventId | string | — | Controlled highlight, drawn with the same focus-ring treatment as keyboard focus. |
| locale | string | "en-US" | BCP 47 locale for day/time label formatting. |