Vize

Scheduler

Headless, SSR-deterministic day/week/month scheduler with a pure event layout engine.

Package @vizejs/ui/scheduler
Maturity stable
Own the source vize lib pull scheduler
Requires calendar, context, controllable-state, datetime-field, drag-and-drop, id, locale
Aliases calendar view, event calendar, agenda, week planner, big calendar
Covers FullCalendar views, React Big Calendar, WAI-ARIA grid, Google Calendar layout

Usage

import { Scheduler, SchedulerRoot, SchedulerDayColumn, SchedulerEvent, SchedulerHeading, SchedulerMonthDay, SchedulerMonthGrid, SchedulerNav, SchedulerTimeGrid } from "@vizejs/ui/scheduler";

Or copy the source into your project with vize lib pull scheduler (see Source Distribution).

API

Scheduler<Data>

Source: src/families/date-time/scheduler/scheduler-root.vue

Props

Prop Type Default Description
id string | null | undefined undefined Consumer-owned base id; nullish values use a deterministic fallback.
events readonly SchedulerEvent<Data>[] | undefined [] Events to lay out; data keeps the consumer payload type.
view SchedulerView | undefined undefined Controlled view; undefined selects uncontrolled mode.
defaultView SchedulerView | undefined "week" Initial uncontrolled view.
date PlainDate | null | undefined undefined Controlled anchor date deciding the visible period.
defaultDate PlainDate | null | undefined undefined Initial uncontrolled anchor date.
today PlainDate | null | undefined undefined Explicit current date; the SSR-safe way to anchor and mark today.
now DateTimeNow | undefined undefined Injectable clock evaluated during setup on server and client.
timeZone string | undefined undefined IANA time zone used with now and the post-mount host clock.
locale string | undefined undefined BCP 47 locale; defaults to the nearest LocaleProvider.
dir "ltr" | "rtl" | undefined undefined Text direction; defaults to the nearest LocaleProvider.
weekStartsOn Weekday | undefined undefined First day of week; defaults to the locale preference.
dayStartHour number | undefined 0 First visible hour of the time grid.
dayEndHour number | undefined 24 Hour where the time grid ends, exclusive.
slotMinutes number | undefined 30 Minutes per time-grid slot row.
snapMinutes number | undefined slotMinutes Minutes that drag and keyboard moves snap to.
minimumEventMinutes number | undefined 15 Minimum rendered event length in minutes.
maxLanes number | undefined 3 Month-view lanes rendered per week before counting overflow.
disabled boolean | undefined false Disable navigation, activation, and editing.
readOnly boolean | undefined false Keep navigation and activation but block move and resize requests.
ariaLabel string | undefined undefined Accessible name for the scheduler region.

Events

Event Payload Description
update:view [view: SchedulerView] Fired when the scheduler requests a new controlled view.
update:date [date: PlainDate] Fired when navigation requests a new anchor date.
event-activate [event: SchedulerEvent<Data>, nativeEvent: Event] Fired when an event is clicked or activated with Enter/Space.
slot-activate [range: SchedulerSlotRange, nativeEvent: Event] Fired when a time-grid slot is clicked or activated.
day-activate [date: PlainDate, nativeEvent: Event] Fired when a month-view day is clicked or activated.
event-move [change: SchedulerEventChange<Data>, nativeEvent: Event | null] Fired when a drag or Alt+Arrow requests a new start (duration preserved).
event-resize [change: SchedulerEventChange<Data>, nativeEvent: Event | null] Fired when a resize drag or Alt+Shift+Arrow requests a new end.

Slots

Slot Slot props Description
default SchedulerSlotState<Data> Scheduler composition. Receives typed layout state; defaults to a header plus the view's grid.

SchedulerRoot<Data>

Source: src/families/date-time/scheduler/scheduler-root.vue

Props

Prop Type Default Description
id string | null | undefined undefined Consumer-owned base id; nullish values use a deterministic fallback.
events readonly SchedulerEvent<Data>[] | undefined [] Events to lay out; data keeps the consumer payload type.
view SchedulerView | undefined undefined Controlled view; undefined selects uncontrolled mode.
defaultView SchedulerView | undefined "week" Initial uncontrolled view.
date PlainDate | null | undefined undefined Controlled anchor date deciding the visible period.
defaultDate PlainDate | null | undefined undefined Initial uncontrolled anchor date.
today PlainDate | null | undefined undefined Explicit current date; the SSR-safe way to anchor and mark today.
now DateTimeNow | undefined undefined Injectable clock evaluated during setup on server and client.
timeZone string | undefined undefined IANA time zone used with now and the post-mount host clock.
locale string | undefined undefined BCP 47 locale; defaults to the nearest LocaleProvider.
dir "ltr" | "rtl" | undefined undefined Text direction; defaults to the nearest LocaleProvider.
weekStartsOn Weekday | undefined undefined First day of week; defaults to the locale preference.
dayStartHour number | undefined 0 First visible hour of the time grid.
dayEndHour number | undefined 24 Hour where the time grid ends, exclusive.
slotMinutes number | undefined 30 Minutes per time-grid slot row.
snapMinutes number | undefined slotMinutes Minutes that drag and keyboard moves snap to.
minimumEventMinutes number | undefined 15 Minimum rendered event length in minutes.
maxLanes number | undefined 3 Month-view lanes rendered per week before counting overflow.
disabled boolean | undefined false Disable navigation, activation, and editing.
readOnly boolean | undefined false Keep navigation and activation but block move and resize requests.
ariaLabel string | undefined undefined Accessible name for the scheduler region.

Events

Event Payload Description
update:view [view: SchedulerView] Fired when the scheduler requests a new controlled view.
update:date [date: PlainDate] Fired when navigation requests a new anchor date.
event-activate [event: SchedulerEvent<Data>, nativeEvent: Event] Fired when an event is clicked or activated with Enter/Space.
slot-activate [range: SchedulerSlotRange, nativeEvent: Event] Fired when a time-grid slot is clicked or activated.
day-activate [date: PlainDate, nativeEvent: Event] Fired when a month-view day is clicked or activated.
event-move [change: SchedulerEventChange<Data>, nativeEvent: Event | null] Fired when a drag or Alt+Arrow requests a new start (duration preserved).
event-resize [change: SchedulerEventChange<Data>, nativeEvent: Event | null] Fired when a resize drag or Alt+Shift+Arrow requests a new end.

Slots

Slot Slot props Description
default SchedulerSlotState<Data> Scheduler composition. Receives typed layout state; defaults to a header plus the view's grid.

SchedulerDayColumn

Source: src/families/date-time/scheduler/scheduler-day-column.vue

Props

Prop Type Default Description
column (required) SchedulerDayColumnState<unknown> undefined (required) Day and timed placements rendered by this column.

Slots

Slot Slot props Description
event TimeGridPlacement<unknown> Event content for each placement; defaults to the event title.

SchedulerEvent

Source: src/families/date-time/scheduler/scheduler-event.vue

Props

Prop Type Default Description
event (required) SchedulerEvent<unknown> undefined (required) Event rendered by this item.
placement TimeGridPlacement<unknown> | undefined undefined Time-grid placement; drives --vize-scheduler-* position variables.
row RowPlacement<unknown> | undefined undefined Row placement for all-day lanes and month weeks.
resizable boolean true Render a resize handle at the end of time-grid events.

Slots

Slot Slot props Description
default { readonly event: SchedulerEvent<unknown>; readonly placement: TimeGridPlacement<unknown> | undefined; readonly row: RowPlacement<unknown> | undefined; readonly label: string; } Event content. Receives the event and its placement; defaults to the title.

SchedulerHeading

Source: src/families/date-time/scheduler/scheduler-heading.vue

Slots

Slot Slot props Description
default { readonly heading: string } Heading content. Receives the localized period label.

SchedulerMonthDay

Source: src/families/date-time/scheduler/scheduler-month-day.vue

Props

Prop Type Default Description
week (required) SchedulerWeekState<unknown> undefined (required) Week row that owns this day.
index (required) number undefined (required) Day index inside the week.

Slots

Slot Slot props Description
day SchedulerDay Day number content.
event RowPlacement<unknown> Event bar content for events starting in this cell.
more { readonly count: number; readonly day: SchedulerDay } Overflow indicator content when more events exist than maxLanes.

SchedulerMonthGrid

Source: src/families/date-time/scheduler/scheduler-month-grid.vue

Slots

Slot Slot props Description
weekday SchedulerDay Weekday column header content.
day SchedulerDay Day number content.
event RowPlacement<unknown> Event bar content.
more { readonly count: number; readonly day: SchedulerDay } Overflow indicator content.

SchedulerNav

Source: src/families/date-time/scheduler/scheduler-nav.vue

Props

Prop Type Default Description
action (required) "previous" | "next" | "today" undefined (required) Navigation performed by the button.
ariaLabel string undefined Accessible name; defaults to "Previous period", "Next period", or "Today".

Slots

Slot Slot props Description
default { readonly action: "previous" | "next" | "today" } Button content. Receives the action.

SchedulerTimeGrid

Source: src/families/date-time/scheduler/scheduler-time-grid.vue

Props

Prop Type Default Description
timeHeader string "Time" Corner column header announced for the time labels.
allDayLabel string "All day" Accessible name of the all-day lane group.

Slots

Slot Slot props Description
dayHeader SchedulerDay Day column header content.
time SchedulerSlotRow Time label content for each slot row.
event TimeGridPlacement<unknown> Timed event content.
allDayEvent RowPlacement<unknown> All-day event content.

Behavior

Normative state x input -> outcome table for the headless Scheduler compound (@vizejs/ui/scheduler): scheduler-root.vue (generic over the event payload Data), scheduler-heading.vue, scheduler-nav.vue, scheduler-time-grid.vue, scheduler-day-column.vue, scheduler-month-grid.vue, scheduler-month-day.vue, and scheduler-event.vue, plus the pure layout engine scheduler-layout.ts. Every row is proven by the named test.

# State Input Outcome Proven by
S1 layout overlapping timed events events sort by start (longer first), group into overlap clusters, take the first free column, and widen across free columns; top/height are fractions of the visible window overlapping events split into columns and widen into free space, three-way overlaps widen short events into free columns
S2 layout window / short / overnight / all-day placements clip to dayStartHour–dayEndHour with continuation flags, get a minimum rendered length, and skip all-day events the day window clips events, enforces a minimum length, and skips all-day events
S3 layout multi-day and all-day events row layout stacks events into lanes (longer first) with continuation flags across the row row layout stacks multi-day events into lanes with continuation flags
S4 layout views / anchors / pointer visibleDays, monthWeeks, shiftAnchor (clamping month days), snapMinute, and minuteAtPoint are pure and deterministic views, month rows, anchors, snapping, and pointer mapping are deterministic
S5 week view render a role="region" holds a <table role="grid"> labelled by the live heading: day column headers (aria-current="date" on today), time row headers, and one roving tabindex=0 slot button; events render in day columns with --vize-scheduler-top/height/column/columns/span, and all-day events in a labelled lane group with --vize-scheduler-start/end/lane week view renders an APG slot grid, day columns, laid-out events, and all-day lanes
S6 time grid Arrow / Home / End / PageUp / PageDown / Enter ±slot, ±day (RTL flips), first/last slot, ±period; leaving the visible days moves the anchor (update:date); Enter/Space/click emits slot-activate with a { start, end } range slot keyboard navigation moves by slot, day, edges, and period, and activation emits a range
S7 events click / Enter / Alt+Arrow / Alt+Shift+Arrow activation emits the typed event; Alt+Up/Down moves by snapMinutes, Alt+Left/Right by a day, Alt+Shift+Up/Down resizes the end (never below start + snapMinutes); read-only blocks requests and hides resize handles events activate and Alt+Arrow keys request typed moves and resizes
S8 events pointer drag (drag-and-drop) dragging an event to a day column emits event-move snapped to the pointer (grab offset kept, duration preserved); dragging the resize handle emits event-resize ending at the pointer's slot pointer drags move and resize events through drop targets
S9 month view render / keyboard / Alt+Arrow week rows with weekday headers and adjacent-month flags; events beyond maxLanes count into +N; arrows/Home/End/PageUp/PageDown move day focus and cross months; Enter emits day-activate; Alt+Down moves an event a week month view lays out week rows, overflow, keyboard day navigation, and day drops
S10 navigation / API nav buttons / controlled view / expose previous, next, and today buttons page the anchor; controlled view emits update:view only; navigate, goToToday, setDate, setView, and focus are exposed; disabled schedulers disable slots navigation controls, controlled view, pending without a clock, and the exposed API
S11 composition default and part slots the root slot receives SchedulerSlotState<Data> with typed payloads; grid parts accept slot content custom composition exposes typed slot state and individual parts
S12 SSR isolated requests / hydration week, day, and month render byte-identically and hydrate silently; without today/now the server renders a pending shell renders byte-identical week, day, and month markup with deterministic layout, hydrates every view without mismatches, without today or now the server renders a pending shell and hydrates silently

SSR determinism

Layout is a pure function of the events, the anchor date, and props. The anchor comes from date, then defaultDate, then the calendar "today" rules (today, then an injected now + timeZone, then the client clock after mount). Drag-and-drop listeners attach only on the client.

Headless positioning

Consumers position events with CSS custom properties. Time-grid events expose --vize-scheduler-top and --vize-scheduler-height (percent of the day column), plus --vize-scheduler-column, --vize-scheduler-columns, and --vize-scheduler-span. Row events expose --vize-scheduler-start and --vize-scheduler-end (CSS grid lines) and --vize-scheduler-lane. The time grid root also exposes --vize-scheduler-days and --vize-scheduler-slots.