
| Demo | |
|---|---|
| Downloads | |
| Languages | JavaScript |
| Technologies | Vue.js |
Features
-
Vue scheduler component created using DayPilot JavaScript Scheduler
-
The scheduler component displays a hierarchy of resources on the vertical axis
-
The timeline is displayed on the horizontal axis
-
The appearance and behavior can be customized easily
-
Full drag and drop support
-
The Vue.js project was generated using Scheduler UI Builder
-
Complete Vue.js application is available for download
License
Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript.
TLDR: Skip This Tutorial and Generate a Customized Vue.js Project
You can use the online Scheduler UI Builder application to create a customized Scheduler configuration using a visual configurator tool with live preview. Generate and download a complete Vue 3 project with all dependencies.
NPM Dependencies
First, add daypilot-pro-vue package from npm.daypilot.org to your Vue application:
npm install https://npm.daypilot.org/daypilot-pro-vue/trial/2026.3.7040.tar.gz
Vue Application
The first version of our Vue scheduler application is very simple. We display the Scheduler Vue component that we will create in the next step:
App.vue
<template>
<Scheduler />
</template>
<script setup>
import Scheduler from './components/Scheduler.vue'
</script>
Vue Scheduler Component
In this step, we will create a new Vue Scheduler component. Our component will use DayPilotScheduler from daypilot-pro-vue package to render the scheduler UI in the browser.
Template:
<template>
<DayPilotScheduler
...
ref="schedulerRef"
/>
</template>
JavaScript:
<script setup>
import { DayPilot, DayPilotScheduler } from 'daypilot-pro-vue'
import { ref, onMounted, nextTick } from 'vue'
const schedulerRef = ref(null)
// ...
</script>
The component template contains a <DayPilotScheduler> tag. We will pass configuration values as props and use Vue listeners for Scheduler events:
-
Props such as
:timeHeaders="timeHeaders"specify the initial Scheduler configuration. Listeners such as@timeRangeSelected="onTimeRangeSelected"handle interactions. -
The
refattribute lets us access the direct API using theDayPilot.Schedulerobject.
Initial Vue.js Scheduler Configuration
We have added an empty Scheduler to our Vue.js application. It uses the default configuration and the view doesn’t display much. In this step, we will use component props to customize the Scheduler appearance.
You can use props and listeners to set the Scheduler properties and event handlers. This first version specifies only basic properties that define the Scheduler timeline (timeHeaders, scale, days, startDate).
Template and JavaScript:
<template>
<DayPilotScheduler
:timeHeaders="timeHeaders"
scale="Day"
:days="days"
:startDate="startDate"
...
/>
</template>
<script setup>
// ...
const timeHeaders = [{groupBy: "Month"}, {groupBy: "Day", format: "d"}]
const days = DayPilot.Date.today().daysInYear()
const startDate = DayPilot.Date.today().firstDayOfYear()
// ...
</script>
Bind these constants using :timeHeaders="timeHeaders", :days="days", and :startDate="startDate", and set scale="Day". The timeline covers the current year. After mounting, the Scheduler scrolls to the current month.
Accessing the Scheduler Object in Vue
The Scheduler component uses DayPilot.Scheduler internally to create the component. We need a reference to the DayPilot.Scheduler object in order to call its methods using the JavaScript API.
First, we need a reference to the Vue.js scheduler object. We can get it using the ref attribute of the <DayPilotScheduler> element:
<DayPilotScheduler
...
ref="schedulerRef"
/>
Declare the template reference in the setup script. Vue fills it after the component mounts:
const schedulerRef = ref(null)
The DayPilotScheduler Vue.js component stores the internal DayPilot.Scheduler instance in the control property.
const scheduler = schedulerRef.value?.control
Now we can use the scheduler constant to reach the DayPilot.Scheduler object:
onMounted(async () => {
const scheduler = schedulerRef.value?.control
// ...
scheduler.message("Welcome!")
scheduler.scrollTo(DayPilot.Date.today().firstDayOfMonth())
})
The complete component also defines row header columns for Name, Location, and Status. A padlock displays the resource status; it is a visual indicator and does not prevent bookings.
Loading Vue.js Scheduler Resources
In this step, we will create a resources ref and bind it to the :resources prop. The loadResources() function assigns the resource data to resources.value; Vue automatically unwraps the ref in the template:
<template>
<DayPilotScheduler
...
:resources="resources"
...
/>
</template>
<script setup>
// ...
const resources = ref([])
// ...
const loadResources = () => {
resources.value = [
{
name: "Group A", id: "GA", expanded: true, children: [
{name: "Resource 1", id: "R1", location: "Location 1"},
{name: "Resource 2", id: "R2", location: "Location 1"},
{name: "Resource 3", id: "R3", location: "Location 2"},
{name: "Resource 4", id: "R4", location: "Location 2", status: "locked"},
]
},
{
name: "Group B", id: "GB", expanded: true, children: [
{name: "Resource 5", id: "R5", location: "Location 3"},
{name: "Resource 6", id: "R6", location: "Location 3"},
{name: "Resource 7", id: "R7", location: "Location 4"},
{name: "Resource 8", id: "R8", location: "Location 4"},
]
}
]
}
// ...
</script>
Loading Vue.js Scheduler Reservations
Now we will create loadReservations() function that loads the event data to the Scheduler. Normally, this method should load the data from the server side using an HTTP call but we will assign a static array to the events ref in this example. Bind it to the component using :events="events":
<template>
<DayPilotScheduler
...
:events="events"
...
/>
</template>
<script setup>
// ...
const events = ref([])
// ...
const loadReservations = () => {
events.value = [
{
id: 1,
resource: "R1",
start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
end: DayPilot.Date.today().firstDayOfMonth().addDays(7),
text: "Event 1",
color: "#6fa8dc"
},
{
id: 2,
resource: "R1",
start: DayPilot.Date.today().firstDayOfMonth().addDays(9),
end: DayPilot.Date.today().firstDayOfMonth().addDays(12),
text: "Event 2",
color: "#93c47d"
},
// ...
]
}
// ...
</script>
Both loading functions update Vue refs, which pass the data to the Scheduler through its :resources and :events props. There is no need to call update() to load these arrays.
The sample stores reservations in memory. Creation, movement, resizing, color changes, and deletion are lost when the page reloads. Connect these handlers to your server API to persist changes.
Loading the Data during App Initialization
Now we need to add the loading methods to the onMounted lifecycle hook so they will be called during the Vue.js app initialization. Wait for nextTick() to apply the prop changes before scrolling to the current month:
onMounted(async () => {
const scheduler = schedulerRef.value?.control
loadResources()
loadReservations()
await nextTick()
scheduler.message("Welcome!")
scheduler.scrollTo(DayPilot.Date.today().firstDayOfMonth())
})
Reservation Context Menu
In this step, we will add a context menu to the reservations. The context menu will let users change the reservation color and delete it.
The context menu can be defined using the contextMenu prop. Users can activate the context menu by right-clicking the reservation.
We will also add an icon to the right side of the reservation box that will serve as a hint that a context menu is available. The icon can be added by inserting an active area using the onBeforeEventRender handler, connected with :onBeforeEventRender="onBeforeEventRender".
<template>
<DayPilotScheduler
...
:onBeforeEventRender="onBeforeEventRender"
:contextMenu="contextMenu"
...
/>
</template>
<script setup>
// ...
const onBeforeEventRender = args => {
args.data.backColor = args.data.color
args.data.borderColor = "darker"
args.data.fontColor = "#ffffff"
args.data.areas = [
{
top: 10,
right: 6,
width: 20,
height: 20,
symbol: "icons/daypilot.svg#minichevron-down-4",
fontColor: "#999999",
backColor: "#f9f9f9",
borderRadius: "50%",
visibility: "Visible",
action: "ContextMenu",
padding: 1,
style: "border: 2px solid #ccc; cursor:pointer;"
}
]
}
const contextMenu = new DayPilot.Menu({
items: [
{
text: "Delete",
onClick: args => {
const e = args.source
const scheduler = schedulerRef.value?.control
scheduler.events.remove(e)
scheduler.message("Deleted.")
}
},
{
text: "-"
},
{
text: "Blue",
icon: "icon icon-blue",
color: "#6fa8dc",
onClick: args => {
updateColor(args.source, args.item.color)
}
},
{
text: "Green",
icon: "icon icon-green",
color: "#93c47d",
onClick: args => {
updateColor(args.source, args.item.color)
}
},
{
text: "Yellow",
icon: "icon icon-yellow",
color: "#f1c232",
onClick: args => {
updateColor(args.source, args.item.color)
}
},
{
text: "Red",
icon: "icon icon-red",
color: "#dd7e6b",
onClick: args => {
updateColor(args.source, args.item.color)
}
},
]
})
// ...
</script>
The updateColor() function changes the color property of the reservation data object and calls the Scheduler API to update the UI.
const updateColor = (e, color) => {
const scheduler = schedulerRef.value?.control
e.data.color = color
scheduler.events.update(e)
scheduler.message("Color updated")
}
Complete Vue App Source Code
Here you can find the full source code of our Vue.js application.
Scheduler.vue
<template>
<DayPilotScheduler
:timeHeaders="timeHeaders"
scale="Day"
:days="days"
:startDate="startDate"
timeRangeSelectedHandling="Enabled"
:eventHeight="eventHeight"
:durationBarVisible="durationBarVisible"
:eventBorderRadius="eventBorderRadius"
:rowMarginTop="rowMarginTop"
:rowMarginBottom="rowMarginBottom"
:rowHeaderColumns="rowHeaderColumns"
@timeRangeSelected="onTimeRangeSelected"
eventMoveHandling="Update"
@eventMoved="onEventMoved"
eventResizeHandling="Update"
@eventResized="onEventResized"
eventClickHandling="Enabled"
@eventClicked="onEventClicked"
eventHoverHandling="Disabled"
:treeEnabled="treeEnabled"
@beforeRowHeaderRender="onBeforeRowHeaderRender"
:onBeforeEventRender="onBeforeEventRender"
:contextMenu="contextMenu"
:resources="resources"
:events="events"
ref="schedulerRef"
/>
</template>
<script setup>
import { DayPilot, DayPilotScheduler } from 'daypilot-pro-vue'
import { ref, onMounted, nextTick } from 'vue'
const schedulerRef = ref(null)
const resources = ref([])
const events = ref([])
const timeHeaders = [{groupBy: "Month"}, {groupBy: "Day", format: "d"}]
const days = DayPilot.Date.today().daysInYear()
const startDate = DayPilot.Date.today().firstDayOfYear()
const eventHeight = 40
const durationBarVisible = false
const eventBorderRadius = 20
const rowMarginTop = 2
const rowMarginBottom = 2
const rowHeaderColumns = [
{title: "Name", display: "name"},
{title: "Location", display: "location"},
{title: "Status", width: 50}
]
const onTimeRangeSelected = async args => {
const scheduler = schedulerRef.value?.control
const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1")
scheduler.clearSelection()
if (modal.canceled) {
return
}
scheduler.events.add({
start: args.start,
end: args.end,
id: DayPilot.guid(),
resource: args.resource,
text: modal.result,
color: "#6fa8dc"
})
}
const onEventMoved = args => {
args.control.message("Event moved: " + args.e.data.text)
}
const onEventResized = args => {
args.control.message("Event resized: " + args.e.data.text)
}
const onEventClicked = args => {
args.control.message("Event clicked: " + args.e.data.text)
}
const treeEnabled = true
const onBeforeRowHeaderRender = args => {
if (args.row.data.status === "locked") {
args.row.columns[2].areas = [
{
top: "calc(50% - 10px)",
left: "calc(50% - 10px)",
width: 20,
height: 20,
symbol: "icons/daypilot.svg#padlock",
fontColor: "#999999",
visibility: "Visible",
}
]
}
}
const onBeforeEventRender = args => {
args.data.backColor = args.data.color
args.data.borderColor = "darker"
args.data.fontColor = "#ffffff"
args.data.areas = [
{
top: 10,
right: 6,
width: 20,
height: 20,
symbol: "icons/daypilot.svg#minichevron-down-4",
fontColor: "#999999",
backColor: "#f9f9f9",
borderRadius: "50%",
visibility: "Visible",
action: "ContextMenu",
padding: 1,
style: "border: 2px solid #ccc; cursor:pointer;"
}
]
}
const contextMenu = new DayPilot.Menu({
items: [
{
text: "Delete",
onClick: args => {
const e = args.source
const scheduler = schedulerRef.value?.control
scheduler.events.remove(e)
scheduler.message("Deleted.")
}
},
{
text: "-"
},
{
text: "Blue",
icon: "icon icon-blue",
color: "#6fa8dc",
onClick: args => {
updateColor(args.source, args.item.color)
}
},
{
text: "Green",
icon: "icon icon-green",
color: "#93c47d",
onClick: args => {
updateColor(args.source, args.item.color)
}
},
{
text: "Yellow",
icon: "icon icon-yellow",
color: "#f1c232",
onClick: args => {
updateColor(args.source, args.item.color)
}
},
{
text: "Red",
icon: "icon icon-red",
color: "#dd7e6b",
onClick: args => {
updateColor(args.source, args.item.color)
}
},
]
})
const loadReservations = () => {
events.value = [
{
id: 1,
resource: "R1",
start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
end: DayPilot.Date.today().firstDayOfMonth().addDays(7),
text: "Event 1",
color: "#6fa8dc"
},
{
id: 2,
resource: "R1",
start: DayPilot.Date.today().firstDayOfMonth().addDays(9),
end: DayPilot.Date.today().firstDayOfMonth().addDays(12),
text: "Event 2",
color: "#93c47d"
},
{
id: 3,
resource: "R3",
start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
end: DayPilot.Date.today().firstDayOfMonth().addDays(6),
text: "Event 3",
color: "#6fa8dc"
},
{
id: 4,
resource: "R2",
start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
end: DayPilot.Date.today().firstDayOfMonth().addDays(6),
text: "Event 4",
color: "#93c47d"
},
{
id: 5,
resource: "R3",
start: DayPilot.Date.today().firstDayOfMonth().addDays(7),
end: DayPilot.Date.today().firstDayOfMonth().addDays(10),
text: "Event 5",
color: "#f1c232"
},
{
id: 6,
resource: "R3",
start: DayPilot.Date.today().firstDayOfMonth().addDays(12),
end: DayPilot.Date.today().firstDayOfMonth().addDays(15),
text: "Event 6",
color: "#dd7e6b"
},
]
}
const loadResources = () => {
resources.value = [
{
name: "Group A", id: "GA", expanded: true, children: [
{name: "Resource 1", id: "R1", location: "Location 1"},
{name: "Resource 2", id: "R2", location: "Location 1"},
{name: "Resource 3", id: "R3", location: "Location 2"},
{name: "Resource 4", id: "R4", location: "Location 2", status: "locked"},
]
},
{
name: "Group B", id: "GB", expanded: true, children: [
{name: "Resource 5", id: "R5", location: "Location 3"},
{name: "Resource 6", id: "R6", location: "Location 3"},
{name: "Resource 7", id: "R7", location: "Location 4"},
{name: "Resource 8", id: "R8", location: "Location 4"},
]
}
]
}
const updateColor = (e, color) => {
const scheduler = schedulerRef.value?.control
e.data.color = color
scheduler.events.update(e)
scheduler.message("Color updated")
}
onMounted(async () => {
const scheduler = schedulerRef.value?.control
loadResources()
loadReservations()
await nextTick()
scheduler.message("Welcome!")
scheduler.scrollTo(DayPilot.Date.today().firstDayOfMonth())
})
</script>
History
-
September 26, 2026: Upgraded to Vue 3.5 and DayPilot Pro for JavaScript 2026.3.7040. Updated the Scheduler component to use Vue props and refreshed the screenshots.
-
October 1, 2024: Upgraded to DayPilot Pro for JavaScript 2024.4.6180. Additional row header columns defined. Styling updates.
-
November 30, 2023: Switched to Vue 3 Composition API, upgraded to DayPilot Pro for JavaScript 2023.4.5801.
-
June 3, 2021: Upgraded to DayPilot Pro for JavaScript 2021.2.5000; upgraded to Vue 3; using system fonts; switched to SVG icons.
-
December 5, 2020: Using package-based Vue 2 project, upgraded to DayPilot Pro for JavaScript 2020.4.4788.
-
September 24, 2019: Upgraded to DayPilot Pro for JavaScript 2019.3.4012.
-
February 9, 2018: Context menu added.
-
February 5, 2018: Initial release.
DayPilot





