Vesture

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.

Scheduler

Preview

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

PropTypeDefaultDescription
idstringRequired. Must be stable across renders — used for overlap layout, drag tracking, and color hashing.
titlestringRequired. Shown on the event block.
start / endDateRequired.
allDaybooleanRenders in the all-day row instead of the time grid; never draggable.
colorstringOverrides the auto-assigned color (hashed from id into the theme's chart.series1-8 tokens, so the same event always gets the same color).
dataunknownPassthrough slot for your own metadata — Scheduler never reads it.

Scheduler

PropTypeDefaultDescription
eventsSchedulerEvent[]Required.
date / onDateChangeDate / (date: Date) => voidAny date within the displayed week; the prev/next/Today controls call onDateChange.
weekStartsOn0 | 11Sunday or Monday.
startHour / endHournumber0 / 24Visible time range.
slotDurationnumber30Gridline density in minutes; also the drag/resize/keyboard snap increment.
onEventClick(event: SchedulerEvent) => voidFires on a plain click (or Enter/Space) — not fired for a click that ends a drag.
onEventChange(event, newStart: Date, newEnd: Date) => voidFires on drag-move drop, resize-release, or a keyboard move/resize. Scheduler doesn't mutate events — apply the change to your own state.
editablebooleanfalseEnables drag-to-move, drag-to-resize, and their keyboard equivalents on timed events.
minEventDurationnumberslotDurationMinimum minutes a resize can shrink an event to.
selectedEventIdstringControlled highlight, drawn with the same focus-ring treatment as keyboard focus.
localestring"en-US"BCP 47 locale for day/time label formatting.