Scheduler
Scheduler
Start with the basic example, then compare related settings before moving to controlled, asynchronous or combined use cases.
Reading direction
Scheduler inherits dir from the page, a local container, or ConfigProvider. Use the documentation navigation switch to change LTR/RTL at runtime. Month/week/resource columns and horizontal time follow inline start; vertical time continues downwards. Switching direction preserves dates, event data, selection and the horizontal reading offset, and cancels active drag or resize gestures.
Hourly resource timelines support moving events and resizing both start and end, respecting snapDuration, readonly state, milestones and event resizable. Zoom preserves the date at the center of the visible time area. Resource labels stick to inline start; virtual rows and their heading scroll together.
Default overlap layouts use inline start. A custom eventLayout return value keeps the physical meaning of left; callers control that geometry. RTL does not reverse dates, time zones, dependencies or source resource order.
Basic examples
Basic usage
Preview configuration: default-date="2026-09-09".
Views and layout
Layout Groups
Configuration reference for this comparison
| Configuration | Purpose | Related examples |
|---|---|---|
default-date | Initial navigation date | Layout Groups, Without Resources, Resource Week |
default-mode | Default uncontrolled view | Layout Groups, Timeline, Hidden Days |
resources | Currently visible resource rows/columns and local options; a complete directory is unnecessary | Resource Week, Timeline, Now Indicator |
start-hour | Time-grid start hour, 0–23 | Layout Groups, Now Indicator, Stacked Events |
end-hour | Time-grid end hour; greater than start and at most 24 | Layout Groups, Now Indicator, Stacked Events |
modes | Views available for switching | Without Resources, Hidden Days, Now Indicator |
Preview configuration: :default-date="today", default-mode="day", :event-layout="custom ? layout : 'stack'", :show-sidebar="false".
Without Resources
Preview configuration: :modes="['day', 'week', 'month', 'agenda']", default-date="2026-09-09".
Resource Week
Preview configuration: default-date="2026-09-09", :resources="resources".
Timeline
Preview configuration: default-date="2026-09-09", default-mode="resource-timeline", :resources="resources".
Hidden Days
Preview configuration: default-date="2026-09-18", default-mode="month", :modes="['week', 'month', 'agenda']", :hidden-days="hidden".
Now Indicator
Preview configuration: v-model:date="date", :show-now-indicator="enabled", default-mode="resource-day", :modes="['day', 'week', 'resource-day']".
Timeline Groups
Preview configuration: v-model:scale="scale", v-model:expanded-keys="expanded", default-date="2026-09-09", default-mode="resource-timeline".
Stacked Events
readonly: Displays the current value without allowing edits.
Resources and assignments
Resources
Configuration reference for this comparison
| Configuration | Purpose | Related examples |
|---|---|---|
default-date | Initial navigation date | Resources, Resource Cross Groups, Resource Dimensions |
default-mode | Default uncontrolled view | Resources, Resource Cross Groups, Resource Dimensions |
resources | Currently visible resource rows/columns and local options; a complete directory is unnecessary | Resources, Resource Cross Groups, Resource Dimensions |
resource-dimensions | Dimension definitions: { id, label }[] | Resource Cross Groups, Resource Dimensions, Independent Assignments |
resource-filters | Combined resource-dimension filters; supports v-model:resource-filters | Resource Cross Groups, Resource Dimensions, Virtual Resources |
show-assignment-details | Edit resource occupancy and roles | Independent Assignments, Assignment Load |
Preview configuration: default-date="2026-09-09", default-mode="resource-day", :resources="resources", :start-hour="8".
Resource Cross Groups
Preview configuration: data-cross-groups-demo, v-model:resource-filters="filters", :resource-group-dimensions="groupDimensions", default-date="2026-09-22".
Resource Dimensions
Preview configuration: data-dimensions-demo, v-model:resource-filters="filters", v-model:resource-dimension="axis", default-date="2026-09-22".
Independent Assignments
Preview configuration: :resources="resources", :resource-dimensions="dimensions", :resource-group-dimensions="['station', 'person']", default-date="2026-09-22".
Assignment Load
Preview configuration: default-date="2026-09-22", default-mode="resource-timeline", default-scale="hour", :resources="resources".
Virtual Resources
Preview configuration: data-virtual-resources-demo, v-model:resource-filters="filters", :resources="resources", :resource-dimensions="dimensions".
Working hours and capacity
Recurring and date-specific working hours
Configuration reference for this comparison
| Configuration | Purpose | Related examples |
|---|---|---|
default-date | Initial navigation date | Recurring and date-specific working hours, Maintenance, Resource Capacity |
default-mode | Default uncontrolled view | Recurring and date-specific working hours, Maintenance, Resource Capacity |
resources | Currently visible resource rows/columns and local options; a complete directory is unnecessary | Recurring and date-specific working hours, Maintenance, Resource Capacity |
resource-label | Resource field name, such as equipment or meeting room | Recurring and date-specific working hours, Maintenance |
allow-overlap | Allow overlapping times for the same resource | Recurring and date-specific working hours |
Compare recurring hours with date-specific overrides. Attempt creation or editing inside and outside available periods to inspect full-duration validation.
Maintenance
Preview configuration: default-date="2026-09-09", default-mode="resource-timeline", default-scale="hour", resource-label="设备".
Resource Capacity
Preview configuration: :status="span.exceeded ? 'danger' : 'success'", default-date="2026-09-15", default-mode="resource-timeline", default-scale="hour".
Recurrence and calendars
Recurring Events
Configuration reference for this comparison
| Configuration | Purpose | Related examples |
|---|---|---|
default-mode | Default uncontrolled view | Recurring Events, Calendar Recurrence, Business Calendar |
default-date | Initial navigation date | Recurring Events, Business Calendar, Recurrence Following |
model-value | Schedule data; supports v-model and becomes controlled when provided | Calendar Recurrence, Recurrence Following, Zoned Recurrence |
readonly | Viewing/navigation allowed, editing blocked | Calendar Recurrence, Recurrence Following, Zoned Recurrence |
resources | Currently visible resource rows/columns and local options; a complete directory is unnecessary | Recurring Events |
date | Navigation date; supports v-model:date | Calendar Recurrence |
Preview configuration: :options="frequencies", aria-label="重复频率", :min="1", :max="12".
Calendar Recurrence
readonly: Displays the current value without allowing edits.
Business Calendar
Preview configuration: default-date="2026-02-26", default-mode="week", :working-hours="hours", :disabled-ranges="blocked".
Recurrence Following
readonly: Displays the current value without allowing edits.
Zoned Recurrence
readonly: Displays the current value without allowing edits.
Editing and interaction
Drag Feedback
Configuration reference for this comparison
| Configuration | Purpose | Related examples |
|---|---|---|
default-date | Initial navigation date | Drag Feedback, Duplicate Events, Custom Cards |
default-mode | Default uncontrolled view | Drag Feedback, Duplicate Events, Custom Event |
resources | Currently visible resource rows/columns and local options; a complete directory is unnecessary | Drag Feedback, Duplicate Events, Custom Cards |
before-change | Return false to cancel; supports asynchronous interception and save APIs | Custom Event, Custom Editor, External Editor |
resource-label | Resource field name, such as equipment or meeting room | Drag Feedback |
start-hour | Time-grid start hour, 0–23 | Drag Feedback |
step: Controls the allowed increment.
Duplicate Events
Preview configuration: default-date="2026-09-16", default-mode="week", :resources="resources", :before-transaction="persist".
Event Dialog
Event Popover
Custom Cards
Preview configuration: default-date="2026-09-09", :resources="resources".
Custom Event
Preview configuration: default-date="2026-09-09", default-mode="week", :resources="resources".
Custom Editor
Preview configuration: default-date="2026-09-09", default-mode="day", :before-change="beforeChange", :model="event".
External Editor
Preview configuration: :editable="false", default-date="2026-09-09", default-mode="day", :before-change="beforeChange".
Batch History
Preview configuration: v-model:selected-keys="selected", default-date="2026-09-09", default-mode="resource-timeline", :resources="resources".
Atomic Swap
Preview configuration: default-date="2026-09-09", default-mode="resource-day", :resources="[{ id: 'room', label: '会议室 A' }]", :allow-overlap="false".
Interaction Completion
Preview configuration: v-model:mode="mode", default-date="2026-09-22", :slot-duration="60", :snap-duration="15".
Advanced Planning
Preview configuration: default-date="2026-09-22", default-mode="resource-timeline", default-scale="hour", :resources="resources".
Async loading and saving
Async Resources
Configuration reference for this comparison
| Configuration | Purpose | Related examples |
|---|---|---|
default-mode | Default uncontrolled view | Async Resources, Remote Events, Async Change |
resources | Currently visible resource rows/columns and local options; a complete directory is unnecessary | Async Resources, Async Change |
before-change | Return false to cancel; supports asynchronous interception and save APIs | Async Resources, Async Change |
default-date | Initial navigation date | Async Resources, Async Change |
resource-label | Resource field name, such as equipment or meeting room | Async Resources |
request-resources | Query resource candidates by keyword and cursor | Async Resources |
Preview configuration: options, :resources="visibleResources", :resource-label="kind === 'device' ? '设备' : '人员'", :request-resources="requestResources".
Remote Events
readonly: Displays the current value without allowing edits.
Async Change
Preview configuration: :model-value="events", default-date="2026-09-09", default-mode="resource-day", :resources="resources".
Workflows and integration
Equipment
Configuration reference for this comparison
| Configuration | Purpose | Related examples |
|---|---|---|
resources | Currently visible resource rows/columns and local options; a complete directory is unnecessary | Equipment, Task Calendar Details, Task Calendar Workbench |
default-mode | Default uncontrolled view | Equipment, Calendar Integration, Task Calendar Details |
default-date | Initial navigation date | Equipment, Calendar Integration, Task Calendar Details |
editable | Enable the built-in editor; false delegates through editor-request | Task Calendar Details, Task Calendar Workbench |
start-hour | Time-grid start hour, 0–23 | Task Calendar Details, Task Calendar Workbench |
end-hour | Time-grid end hour; greater than start and at most 24 | Task Calendar Details, Task Calendar Workbench |
Preview configuration: :resources="devices", resource-label="设备", default-mode="resource-day", default-date="2026-09-09".
Calendar Integration
Preview configuration: placeholder="ICS 文本", :rows="4", default-date="2026-09-22", default-mode="week".
Task Calendar Details
Preview configuration: :editable="false", :resources="resources", default-date="2026-09-09", default-mode="resource-day".
Task Calendar Workbench
step: Controls the allowed increment.readonly: Displays the current value without allowing edits.disabled: Prevents user interaction.
API
<c-scheduler> Props
| Prop | Description | Type | Default |
|---|---|---|---|
| model-value | Schedule data; supports v-model and becomes controlled when provided | SchedulerEvent[] | — |
| preview-event | Unsaved new-event placeholders; visual only | SchedulerEvent | — |
| default-value | Initial uncontrolled data | SchedulerEvent[] | [] |
| mode | Current view; supports v-model:mode | SchedulerMode | — |
| default-mode | Default uncontrolled view | SchedulerMode | week |
| date | Navigation date; supports v-model:date | Date / string / number | — |
| default-date | Initial navigation date | Date / string / number | Current date |
| resource-dimensions | Dimension definitions: { id, label }[] | SchedulerResourceDimension[] | [] |
| resource-filters | Combined resource-dimension filters; supports v-model:resource-filters | SchedulerResourceFilters | — |
| default-resource-filters | Initial uncontrolled filters | SchedulerResourceFilters | {} |
| resource-dimension | Resource row/column dimension; an empty string shows all | string | — |
| default-resource-dimension | Initial uncontrolled display dimension | string | '' |
| resources | Currently visible resource rows/columns and local options; a complete directory is unnecessary | SchedulerResource[] | [] |
| resource-label | Resource field name, such as equipment or meeting room | string | Localized resource label |
| request-resources | Query resource candidates by keyword and cursor | SchedulerRequestResources | — |
| resolve-resources | Batch-resolve resource names by ID | SchedulerResolveResources | — |
| modes | Views available for switching | SchedulerMode[] | All six views |
| first-day-of-week | Week start: 0 Sunday to 6 Saturday | number | 1 |
| start-hour | Time-grid start hour, 0–23 | number | 8 |
| end-hour | Time-grid end hour; greater than start and at most 24 | number | 20 |
| initial-scroll-minute | Minute of day initially scrolled into view; subsequent renders retain user scroll position | number | — |
| step | Grid/snap interval in minutes; a positive integer dividing 60 | number | 30 |
| slot-duration | Grid interval in minutes; positive integer | number | step |
| snap-duration | Pointer snap interval in minutes; positive integer | number | step |
| default-duration | Default duration for click-to-create, in positive integer minutes | number | step |
| drag-to-create | Drag-select empty slots in day/week/resource-day views | boolean | false |
| month-event-limit | Maximum directly displayed events per month-view day; extra events use Popover | number | 3 |
| overlap-event-limit | Maximum directly displayed events per overlapping time-grid group; extra events use Popover | number | — |
| zoom / default-zoom | Timeline zoom, 0.5–4 | number | 1 |
| show-date-header | Tiered timeline date headers | boolean | true |
| show-assignment-details | Edit resource occupancy and roles | boolean | false |
| show-resource-load | Resource peak load, capacity and utilization within the range | boolean | false |
| rule-policy | allow/warn/block policies for capacity/unavailable/conflict | SchedulerRulePolicy | {}(block) |
| dependencies | Task dependencies | SchedulerDependency[] | [] |
| event-layout | Time-grid layout: stack / columns / geometry callback. Week defaults to stack; others to columns | SchedulerEventLayout | Depends on the view |
| readonly | Viewing/navigation allowed, editing blocked | boolean | false |
| disabled | Disable interaction | boolean | false |
| hidden-days | Hide specified weekdays in week/month/agenda, 0–6; cannot hide every day | number[] | [] |
| show-now-indicator | Show the current local-time line in day/week/resource-day views | boolean | false |
| show-sidebar | Show filters and the unscheduled list | boolean | true |
| allow-overlap | Allow overlapping times for the same resource | boolean | true |
| editable | Enable the built-in editor; false delegates through editor-request | boolean | true |
| before-change | Return false to cancel; supports asynchronous interception and save APIs | SchedulerBeforeChange / SchedulerBeforeChange[] | — |
mode is day | week | month | agenda | resource-day | resource-timeline. Agenda/resource-timeline navigate by week. Events outside time-grid hours remain visible in month/agenda/timeline.
With controlled model-value, the component proposes data and waits for parent acceptance before changing the UI; it does not move first and roll back after request failure. Input arrays/objects are not mutated. before-change receives detached copies; editing them does not alter the committed proposal.
<c-scheduler> Events
| Event | Description | Arguments |
|---|---|---|
| update:model-value | Proposes a new main value | SchedulerEvent[] |
| update:resourceFilters | Combined resource-filter changes; controlled mode waits for parent acceptance | SchedulerResourceFilters |
| update:resourceDimension | Resource row/column display-dimension changes | string |
| update:mode | View changes | SchedulerMode |
| update:zoom | Timeline zoom changes | number |
| rule-warning | Advisory rule issues on an accepted proposal | SchedulerError[] |
| update:date | Navigation-date changes | Date |
| change | Validation/hooks complete; controlled mode has proposed a validated value | value, SchedulerChangeContext |
| change-error | Validation, conflict, save or stale-proposal errors | error, SchedulerChange |
| event-click | Activate an event with a copy; stacked events support click/Enter too, while multiselection does not activate | SchedulerEvent |
| cell-click | Click an empty time slot | SchedulerCell |
| range-change | Initial and actual visible-date-range changes | SchedulerRange |
| resource-error | Resource search/display resolution fails without changing schedule data | error, SchedulerResourceErrorContext |
| editor-request | Only with editable=false: request external creation or viewing/editing | SchedulerEditorRequest |
<c-scheduler> Slots
| Slot | Arguments | Description |
|---|---|---|
| event | { event } | Event-button content |
| sidebar | { startDrag, cancelDrag, disabled, unscheduled } | Replace the entire sidebar, e.g. with a resource tree/task pool; hidden when show-sidebar=false |
| sidebar-extra | { startDrag, cancelDrag, disabled } | Content above the default sidebar; startDrag(template: SchedulerEventTemplate, event: DragEvent). Hidden when show-sidebar=false |
| resource-header | { resource?, resources?, date } | Resource or date header |
| toolbar | { date, mode, navigate, create } | Replace the toolbar; navigate(-1/1) changes range, create() follows toolbar creation |
| column-background | { date, resource? } | Background for day/week/resource-day columns without intercepting pointers; useful for soft warnings/heatmaps |
| toolbar-extra | { date, mode } | Toolbar extension |
| editor | SchedulerEditorSlotProps | Custom drawer content: action, event, error, errorMessage, save, remove, close, readonly, pending |
| empty | — | Empty state |
Instance methods
| Method | Description |
|---|---|
change(change): Promise<boolean> | Execute create/update/remove/move/resize with all validation/hooks |
| duplicateEvent(id: string) | Open a separately copied draft or request custom creation; returns boolean without automatically saving |
| goToDate(date: Date) | Navigate to a date; respects controlled models |
Type definitions
import type {
SchedulerProps,
SchedulerInstance,
SchedulerMode,
SchedulerEvent,
SchedulerResource,
SchedulerChange,
SchedulerChangeContext,
SchedulerBeforeChange,
SchedulerEventTemplate,
SchedulerRequestResources,
SchedulerResolveResources,
SchedulerResourcePage,
SchedulerResourceQuery,
SchedulerResourceErrorContext,
SchedulerEditorRequest,
SchedulerEditorAction,
SchedulerEditorSlotProps,
} from "@cedar-design/ui";
interface SchedulerEvent {
id: string;
title: string;
start?: Date | string | number;
end?: Date | string | number;
allDay?: boolean;
resourceIds?: string[];
resourceDetails?: Record<string, { units?: number; role?: string }>;
milestone?: boolean;
layoutGroupId?: string;
description?: string;
color?: string;
accentColor?: string;
backgroundColor?: string;
backgroundPattern?: "solid" | "diagonal-stripes" | "dots" | "crosshatch";
metadata?: Record<string, unknown>;
readonly?: boolean;
resizable?: boolean; // false disables time-grid resizing while preserving moving/viewing
}
type SchedulerEventTemplate = Pick<
SchedulerEvent,
| "title"
| "description"
| "color"
| "accentColor"
| "backgroundColor"
| "backgroundPattern"
| "metadata"
| "resourceIds"
> & {
duration?: number; // positive minutes; defaults to default-duration or step
};
interface SchedulerResource {
id: string;
dimensionId?: string;
label: string;
color?: string;
disabled?: boolean;
capacity?: number; // nonnegative safe integer; omission leaves concurrent event counts unlimited
}
interface SchedulerResourceQuery {
dimensionId?: string;
query: string;
cursor?: string;
signal: AbortSignal;
}
interface SchedulerResourcePage {
items: SchedulerResource[];
nextCursor?: string;
}
type SchedulerRequestResources = (
query: SchedulerResourceQuery,
) => SchedulerResourcePage | Promise<SchedulerResourcePage>;
type SchedulerResolveResources = (
ids: string[],
context: { signal: AbortSignal },
) => SchedulerResource[] | Promise<SchedulerResource[]>;
type SchedulerResourceErrorContext =
| { type: "search"; query: string; cursor?: string }
| { type: "resolve"; ids: string[] };
type SchedulerEditorAction = "create" | "edit";
type SchedulerEditorRequest = { event: SchedulerEvent; readonly: boolean } & (
| { action: "create"; source: "toolbar" | "cell" | "drop" }
| { action: "edit"; source: "event" }
);
interface SchedulerEditorSlotProps {
action: SchedulerEditorAction;
event: SchedulerEvent;
error?: SchedulerError;
errorMessage?: string;
readonly: boolean;
pending: boolean;
save: (event?: SchedulerEvent) => void;
remove: () => void;
close: () => void;
}
Every event id must be unique. Omitting both start/end means unscheduled; otherwise end must follow start, except timed milestones requiring start=end. All intervals are [start, end), so adjacent intervals do not conflict. allDay uses YYYY-MM-DD strings with an exclusive end, e.g. September 9–10 for a one-day event.
Display currently uses the runtime's local zone; timed events should use ISO instants. Arbitrary IANA display zones are not promised. Cross-zone RRULE, ICS and version synchronization come from separate adapters; business code must connect real external accounts. Configure virtual resource rows with virtual-list-props. See examples for local undo and range-based remote loading. Pointer drag supports moving/resizing; Escape cancels. Keyboard/touch users can also schedule/assign through the editor. Disabled resource options prevent new assignments/drops while existing associations may remain or be removed.
Independent core
src/scheduler/core imports no Vue, DOM or external calendar library. It can be tested independently and later extracted as scheduler-core. The published pure-core subentry avoids importing component runtime:
import {
applySchedulerChange,
getSchedulerConflicts,
layoutSchedulerEvents,
} from "@cedar-design/ui/scheduler/core";
Other date/timeline utilities are exported from this entry too. The core computes and applies immutable changes; it does not handle networking, authorization or database transactions.
Style variables
All variables are defined in style/token.less and support light/dark theme overrides.
| Variable | Default |
|---|---|
| --c-scheduler-background | var(--c-color-bg-2) |
| --c-scheduler-color | var(--c-color-text-1) |
| --c-scheduler-border-color | var(--c-color-border) |
| --c-scheduler-sidebar-width | 220px |
| --c-scheduler-slot-height | 36px |
| --c-scheduler-column-min-width | 120px |
| --c-scheduler-max-height | 720px |
| --c-scheduler-event-color | rgb(var(--c-primary-6)) |
| --c-scheduler-event-accent-color | var(--c-scheduler-event-color) |
| --c-scheduler-event-background | var(--c-color-primary-light-1) |
| --c-scheduler-lane-height | 38px |
| --c-scheduler-ghost-opacity | 0.75 |
| --c-scheduler-preview-opacity | 0.85 |
| --c-scheduler-preview-duration | 100ms |
| --c-scheduler-ghost-z-index | 2000 |
Before-hook waiting feedback
Before-hook waits show visible feedback and aria-busy. Rejected or failed operations recover; duplicate submissions do not start another copy. Notification event Promises never drive loading.