DayPilot Vue Scheduler displays a horizontal timeline with people, rooms, machines, or other resources arranged as rows. Use it to build reservation systems, staff schedules, work order boards, and production plans. Users can see how work is allocated over time, select a time slot, and move or resize bookings directly in the schedule.

Choose DayPilot Lite, the open-source edition under the Apache License 2.0, or DayPilot Pro, the commercial edition with additional planning features. Both provide a Vue component, TypeScript definitions, drag-and-drop editing, and Vue templates for custom content.

Try the Lite demo · Try the Pro demo · Configure a Scheduler in UI Builder

Vue Scheduler Component (DayPilot)

This Pro example groups resources into a tree and displays additional resource details beside the timeline.

Vue Scheduler Features

DayPilot Lite and Pro

  • Resource scheduling on a horizontal timeline. Compare bookings or tasks across multiple resources. Choose a time scale and combine time-header rows to show dates and periods. Add date-navigation buttons or a Vue date picker to change the displayed range.

  • Drag-and-drop editing. Let users select a time range, move an event to another date or resource, and resize it to change its duration. Callbacks connect these actions to your Vue application and backend. The Scheduler supports mouse and touch interaction.

  • Vue templates and event actions. Render event details, buttons, status badges, and other custom content using Vue slots. Customize events, cells, and headers, add an event context menu, and use CSS themes to match your application.

  • Working time and availability. Highlight business hours, weekends, holidays, and other periods. Your application supplies resource availability and booking rules; the holiday tutorial below shows resource-specific highlighting and validation.

  • Progressive rendering. The Scheduler renders row headers and events as users scroll. This reduces the number of displayed elements; it does not by itself reduce the amount of data downloaded from your backend.

Additional DayPilot Pro Features

  • Grouped resources and summary rows. Organize teams, rooms, or equipment into an expandable resource tree. Display extra resource fields in row header columns and keep selected rows fixed at the top or bottom for summaries or priority resources.

  • Feedback during drag and drop. Check proposed positions while an event is moving or resizing, reject invalid positions, and explain the reason. Moving customization and validation callbacks let you apply your application's time, resource, and capacity rules.

  • Custom timelines and loading during scrolling. Build a manual timeline, hide non-business periods, or use infinite scrolling. With dynamic event loading, your application can fetch events for the viewport instead of downloading the whole schedule at once.

  • Related and unscheduled work. Draw links between events and combine Scheduler with the Vue Queue component for work waiting to be assigned. Links show relationships; your application controls any resulting date changes or dependency rules.

  • Planned versus actual. Use event versions to keep the original task or booking visible alongside its changed schedule.

  • Export and keyboard navigation. Create an image, a PDF, or an Excel spreadsheet using the format-specific export guides. Enable keyboard support for navigation and time-range selection, and configure it to work with the surrounding application.

See Scheduler features, the Pro feature demos, and the edition comparison for more detail. For a day/week calendar with time running vertically and resources as columns, use the Vue Calendar.

Vue Scheduler Demos and Tutorials

Explore complete Vue projects for resource reservations, custom event content, and scheduling workflows. The examples use Vue 3. Each application supplies its own data and business rules.

Start with Vue Scheduler

Custom Content and Editing

Scheduling Workflows and Backend Data

Configure a Vue Scheduler in UI Builder

Scheduler UI Builder lets you choose the timeline, appearance, and interactions, then generate a downloadable Vue project. Use it to explore options before adding application-specific data and backend calls.

Installation

DayPilot Lite

Install @daypilot/daypilot-lite-vue from npm:

npm install @daypilot/daypilot-lite-vue

DayPilot Pro

At npm.daypilot.org, select Vue and copy the installation command for daypilot-pro-vue. Licensed customers can obtain their package URL in the customer area.

The examples use Vue 3 and the Composition API with <script setup>.

Display Room Reservations

Two rooms appear as rows. Each cell is one day, so the multi-day bookings are easy to see.

Scheduler.vue

<script setup>
import {ref} from 'vue';
import {DayPilot, DayPilotScheduler} from '@daypilot/daypilot-lite-vue';

const events = ref([
  {id: 1, text: 'Reservation A', resource: 'R1',
    start: '2026-10-05', end: '2026-10-08'},
  {id: 2, text: 'Reservation B', resource: 'R2',
    start: '2026-10-20', end: '2026-10-23'}
]);

const resources = ref([{id: 'R1', name: 'Room 1'}, {id: 'R2', name: 'Room 2'}]);
</script>

<template>
  <DayPilotScheduler
    startDate="2026-10-01"
    :days="31"
    scale="Day"
    :timeHeaders="[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]"
    :events="events"
    :resources="resources"
  />
</template>

The resource on each event matches a resource ID. startDate, days and scale define the timeline; timeHeaders label its month and days. Reservation A occupies October 5–7 because its end is exclusive.

The examples use Lite. For Pro, change the package import to daypilot-pro-vue.

See event loading and resource loading for data formats and loading options.

Navigate and Load Reservations

Previous and Next change the month and load its reservations. The endpoint returns {resources: [...], events: [...]}; keeping both collections in the same response avoids showing bookings against an unrelated resource list.

SchedulerLoading.vue

<script setup>
import {ref, watch} from 'vue';
import {DayPilot, DayPilotScheduler} from '@daypilot/daypilot-lite-vue';

const startDate = ref(new DayPilot.Date('2026-10-01'));

const events = ref([]);

const resources = ref([]);

watch(startDate, async (_, __, onCleanup) => {
  let active = true;
  onCleanup(() => { active = false; });
  const start = startDate.value;
  const end = start.addMonths(1);
  const url = `/api/schedule?start=${start}&end=${end}`;
  try {
    const {data} = await DayPilot.Http.get(url);
    if (!active) { return; }
    resources.value = data.resources;
    events.value = data.events;
  } catch {
    if (active) { await DayPilot.Modal.alert('Could not load data.'); }
  }
}, {immediate: true, flush: 'post'});

function navigate(offset) {
  startDate.value = startDate.value.addMonths(offset);
}
</script>

<template>
  <button @click="navigate(-1)">Previous month</button>
  <button @click="navigate(1)">Next month</button>
  <DayPilotScheduler
    :startDate="startDate"
    :days="startDate.daysInMonth()"
    scale="Day"
    :timeHeaders="[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]"
    :events="events"
    :resources="resources"
  />
</template>

The /api/schedule URL represents your own backend. Return items that overlap the requested range: item start is before the requested end, and item end is after the requested start. Failed requests display a DayPilot dialog.

The watcher cleanup prevents an older response from replacing data after another navigation action.

For large schedules, Pro also supports dynamic event loading as the user scrolls. That is separate from replacing the events for a new month.

Create Reservations by Selecting Time

This complete variation of the first example handles time range selection. The selection supplies the dates and resource; the dialog supplies the name.

SchedulerCreation.vue

<script setup>
import {ref} from 'vue';
import {DayPilot, DayPilotScheduler} from '@daypilot/daypilot-lite-vue';

const events = ref([
  {id: 1, text: 'Reservation A', resource: 'R1',
    start: '2026-10-05', end: '2026-10-08'},
  {id: 2, text: 'Reservation B', resource: 'R2',
    start: '2026-10-20', end: '2026-10-23'}
]);

const resources = ref([{id: 'R1', name: 'Room 1'}, {id: 'R2', name: 'Room 2'}]);

async function onTimeRangeSelected(args) {
  const modal = await DayPilot.Modal.prompt('Reservation name:', 'New reservation');
  args.control.clearSelection();
  if (modal.canceled) { return; }
  args.control.events.add({
    id: DayPilot.guid(), text: modal.result,
    start: args.start, end: args.end, resource: args.resource
  });
}
</script>

<template>
  <DayPilotScheduler
    startDate="2026-10-01"
    :days="31"
    scale="Day"
    :timeHeaders="[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]"
    :events="events"
    :resources="resources"
    @timeRangeSelected="onTimeRangeSelected"
  />
</template>

Canceling the dialog leaves the data unchanged. events.add() inserts the new event locally. In an application with a backend, create the record with a POST request and use the returned ID before adding it to the view.

Move, Resize and Save Events

Moving changes the event position; resizing changes its duration. Both work in the first example without extra configuration. The component updates the display and the supplied data object automatically.

Use the callbacks after the edit to persist the result. This example sends the changed record to the backend; it does not reload the collection after each drag.

SchedulerSaving.vue

<script setup>
import {ref} from 'vue';
import {DayPilot, DayPilotScheduler} from '@daypilot/daypilot-lite-vue';

const events = ref([
  {id: 1, text: 'Reservation A', resource: 'R1',
    start: '2026-10-05', end: '2026-10-08'},
  {id: 2, text: 'Reservation B', resource: 'R2',
    start: '2026-10-20', end: '2026-10-23'}
]);

const resources = ref([{id: 'R1', name: 'Room 1'}, {id: 'R2', name: 'Room 2'}]);

async function saveEvent(data) {
  try {
    await DayPilot.Http.put(`/api/events/${data.id}`, data);
  } catch {
    await DayPilot.Modal.alert('The change could not be saved.');
  }
}
</script>

<template>
  <DayPilotScheduler
    startDate="2026-10-01"
    :days="31"
    scale="Day"
    :timeHeaders="[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]"
    :events="events"
    :resources="resources"
    @eventMoved="saveEvent($event.e.data)"
    @eventResized="saveEvent($event.e.data)"
  />
</template>

The /api/events/{id} endpoint accepts the updated JSON record. A failed save is reported while the local edit remains visible; add retry or rollback behavior to suit your application. To disable an interaction, set eventMoveHandling or eventResizeHandling to "Disabled".

Handle a Event Click

To display the clicked item’s name, add this listener to the existing component tag:

@eventClick="DayPilot.Modal.alert(DayPilot.Util.escapeHtml($event.e.text()))"

DayPilot.Modal.alert() accepts HTML. escapeHtml() displays the item’s name as plain text.

Render Custom Vue Content

This independent variation of the first example adds a scoped slot for the event content.

SchedulerContent.vue

<script setup>
import {ref} from 'vue';
import {DayPilot, DayPilotScheduler} from '@daypilot/daypilot-lite-vue';

const events = ref([
  {id: 1, text: 'Reservation A', resource: 'R1',
    start: '2026-10-05', end: '2026-10-08'},
  {id: 2, text: 'Reservation B', resource: 'R2',
    start: '2026-10-20', end: '2026-10-23'}
]);

const resources = ref([{id: 'R1', name: 'Room 1'}, {id: 'R2', name: 'Room 2'}]);
</script>

<template>
  <DayPilotScheduler
    startDate="2026-10-01"
    :days="31"
    scale="Day"
    :timeHeaders="[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]"
    :events="events"
    :resources="resources"
  >
    <template #event="{event}">
      <strong>{{ event.text() }}</strong>
    </template>
  </DayPilotScheduler>
</template>

Scheduler supports event, cell, rowHeader and timeHeader templates in both editions. The row-header slot receives row; Pro also supplies x for the row-header column index.

For the upper-left corner above the row headers, use cornerHtml. Pro also supports a corner template, which has no slot arguments. Add a ref for an editable label:

Lite event/cell templates are supported since 4.7.0, and row-header/time-header templates since 5.10.0. Pro event/cell/row-header/time-header templates are supported since 2024.4.6243.

In Pro, templates also track reactive parent data: changing a value used inside a template refreshes its content automatically. The wrapper handles mounting and cleanup of template content.

Add a Reactive Corner Label (Pro)

The Pro corner slot displays Vue content above the resource names. This example lets the user edit that label. For a fixed HTML label, use cornerHtml.

SchedulerCorner.vue

<script setup>
import {ref} from 'vue';
import {DayPilot, DayPilotScheduler} from 'daypilot-pro-vue';

const events = ref([
  {id: 1, text: 'Reservation A', resource: 'R1',
    start: '2026-10-05', end: '2026-10-08'},
  {id: 2, text: 'Reservation B', resource: 'R2',
    start: '2026-10-20', end: '2026-10-23'}
]);

const resources = ref([{id: 'R1', name: 'Room 1'}, {id: 'R2', name: 'Room 2'}]);

const cornerLabel = ref('Rooms');
</script>

<template>
  <input v-model="cornerLabel" aria-label="Corner label">
  <DayPilotScheduler
    startDate="2026-10-01"
    :days="31"
    scale="Day"
    :timeHeaders="[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]"
    :events="events"
    :resources="resources"
  >
    <template #corner>{{ cornerLabel }}</template>
  </DayPilotScheduler>
</template>

Access the Scheduler API

Find Reservation B by ID and scroll the timeline to its start. This is useful when a booking or task lies outside the current horizontal viewport.

SchedulerApi.vue

<script setup>
import {ref} from 'vue';
import {DayPilot, DayPilotScheduler} from '@daypilot/daypilot-lite-vue';

const scheduler = ref(null);

const events = ref([
  {id: 1, text: 'Reservation A', resource: 'R1',
    start: '2026-10-05', end: '2026-10-08'},
  {id: 2, text: 'Reservation B', resource: 'R2',
    start: '2026-10-20', end: '2026-10-23'}
]);

const resources = ref([{id: 'R1', name: 'Room 1'}, {id: 'R2', name: 'Room 2'}]);

function showReservation() {
  const control = scheduler.value.control;
  const event = control.events.find(2);
  control.scrollTo(event.start());
}
</script>

<template>
  <button @click="showReservation">Show reservation B</button>
  <DayPilotScheduler
    startDate="2026-10-01"
    :days="31"
    scale="Day"
    :timeHeaders="[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]"
    :events="events"
    :resources="resources"
    ref="scheduler"
  />
</template>

The Vue template ref exposes the underlying control as scheduler.value.control. The wrapper creates and disposes it. See the DayPilot.Scheduler API for methods, properties and callbacks.

Use the Options API

The Options API uses the same properties and listeners. Register the component, return the collections from data(), and define handlers in methods. This is a complete alternative to the first Composition API example.

SchedulerOptions.vue

<script>
import {DayPilot, DayPilotScheduler} from '@daypilot/daypilot-lite-vue';

export default {
  components: {DayPilotScheduler},
  data() {
    return {
      resources: [{id: 'R1', name: 'Room 1'}, {id: 'R2', name: 'Room 2'}],
      events: [
  {id: 1, text: 'Reservation A', resource: 'R1',
    start: '2026-10-05', end: '2026-10-08'},
  {id: 2, text: 'Reservation B', resource: 'R2',
    start: '2026-10-20', end: '2026-10-23'}
]
    };
  },
  methods: {
    onEventClick(args) {
      DayPilot.Modal.alert(DayPilot.Util.escapeHtml(args.e.text()));
    }
  }
};
</script>

<template>
  <DayPilotScheduler
    startDate="2026-10-01"
    :days="31"
    scale="Day"
    :timeHeaders="[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]"
    :resources="resources"
    :events="events"
    @eventClick="onEventClick"
  />
</template>

Availability

Availability of this feature in DayPilot editions:

ProductLitePro
DayPilot for JavaScript
DayPilot for ASP.NET WebForms
DayPilot for ASP.NET MVC
DayPilot for Java