Overview
Add a context menu to JavaScript Scheduler events with “Lock” and “Unlock” items.
Users will not be able to move or change the locked events
The context menu is updated dynamically depending on the event status.
Includes the open-source DayPilot Lite for JavaScript scheduling library
Context Menu with “Lock” Item
Lets define a context menu that will allow users lock Scheduler events:
const scheduler = new DayPilot.Scheduler("dp", {
// ...
contextMenu: new DayPilot.Menu({
items: [
{
text: "Lock",
onClick: (args) => {
const e = args.source;
const locked = e.data.tags?.locked;
if (!e.data.tags) {
e.data.tags = {};
}
e.data.tags.locked = !locked;
scheduler.events.update(e);
}
},
{
text: "-"
},
{
text: "Edit...",
onClick: (args) => {
app.editEvent(args.source);
}
},
],
}),
// ...
});
The onClick
event handler of the “Lock” menu item sets the locked
custom property to true
. The custom property is saved under tags
object of the event data object to prevent naming conflicts.
Locking the JavaScript Scheduler Event
We will lock the item using onBeforeEventRender.
const scheduler = new DayPilot.Scheduler("dp", {
// ...
onBeforeEventRender: (args) => {
const locked = args.data.tags?.locked;
if (locked) {
args.data.moveDisabled = true;
args.data.resizeDisabled = true;
args.data.clickDisabled = true;
}
},
// ...
});
If the “locked” status is detected (args.data.tags.locked
) the drag and drop event operations (moving, resizing) are disabled, as well as the click action.
For more options on making the Scheduler events (or the whole Scheduler) read-only please see the following tutorial:
Locked Event Icon
We will also use onBeforeEventRender
event handler to display a padlock icon inside the locked event:
const scheduler = new DayPilot.Scheduler("dp", {
// ...
onBeforeEventRender: (args) => {
const locked = args.data.tags?.locked;
if (locked) {
// ...
args.data.areas = [
{
top: 10,
right: 10,
width: 15,
height: 15,
symbol: "icons/daypilot.svg#padlock"
}
];
}
},
// ...
});
Unlocking the Scheduler Event
We will use the onShow event of the context menu object to change the context menu items depending on the event status.
If the event is locked, the following changes will be made:
The first menu item (“Lock”) text will be changed to “Unlock”
The “Edit…” item will be disabled
const scheduler = new DayPilot.Scheduler("dp", {
// ...
contextMenu: new DayPilot.Menu({
items: [
{
text: "Lock",
onClick: (args) => {
const e = args.source;
const locked = e.data.tags?.locked;
if (!e.data.tags) {
e.data.tags = {};
}
e.data.tags.locked = !locked;
scheduler.events.update(e);
}
},
{
text: "-"
},
{
text: "Edit...",
onClick: (args) => {
app.editEvent(args.source);
}
},
],
onShow: (args) => {
const e = args.source;
const locked = e.data.tags && e.data.tags.locked;
scheduler.contextMenu.items[0].text = locked ? "Unlock" : "Lock";
scheduler.contextMenu.items[2].disabled = locked;
}
}),
// ...
});
Full Source Code
This is the full source code of our example that adds a context menu to the JavaScript Scheduler events with an option to lock the event.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>JavaScript Scheduler: Lock Events using Context Menu</title>
<!-- DayPilot library -->
<script src="js/daypilot/daypilot-all.min.js"></script>
</head>
<body>
<div class="header">
<h1><a href='https://code.daypilot.org/30746/javascript-scheduler-lock-events-using-context-menu'>JavaScript Scheduler: Lock Events using Context Menu</a></h1>
<div><a href="https://javascript.daypilot.org/">DayPilot for JavaScript</a> - HTML5 Calendar/Scheduling Components for JavaScript/Angular/React/Vue</div>
</div>
<div class="main">
<div id="dp"></div>
<div class="generated">Generated using <a href="https://builder.daypilot.org/">DayPilot UI Builder</a>.</div>
</div>
<script>
const scheduler = new DayPilot.Scheduler("dp", {
timeHeaders: [{groupBy: "Month"}, {groupBy: "Day", format: "d"}],
scale: "Day",
days: 31,
startDate: "2026-08-01",
eventBorderRadius: 30,
durationBarVisible: false,
timeRangeSelectedHandling: "Enabled",
onTimeRangeSelected: async (args) => {
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
});
},
onBeforeEventRender: (args) => {
args.data.backColor = "#f1c232aa";
args.data.borderColor = "darker";
args.data.padding = 10;
const locked = args.data.tags?.locked;
if (locked) {
args.data.moveDisabled = true;
args.data.resizeDisabled = true;
args.data.clickDisabled = true;
args.data.areas = [
{
top: 10,
right: 10,
width: 15,
height: 15,
symbol: "icons/daypilot.svg#padlock"
}
];
}
},
onEventClick: (args) => {
editEvent(args.e);
},
contextMenu: new DayPilot.Menu({
items: [
{
text: "Lock",
onClick: (args) => {
const e = args.source;
const locked = e.data.tags?.locked;
if (!e.data.tags) {
e.data.tags = {};
}
e.data.tags.locked = !locked;
scheduler.events.update(e);
}
},
{
text: "-"
},
{
text: "Edit...",
onClick: (args) => {
app.editEvent(args.source);
}
},
],
onShow: (args) => {
const e = args.source;
const locked = e.data.tags && e.data.tags.locked;
scheduler.contextMenu.items[0].text = locked ? "Unlock" : "Lock";
scheduler.contextMenu.items[2].disabled = locked;
}
}),
});
scheduler.init();
const app = {
async editEvent(e) {
const form = [
{name: "Name", id: "text"}
];
const data = e.data;
const modal = await DayPilot.Modal.form(form, data);
if (modal.canceled) {
return;
}
e.data = modal.result;
scheduler.events.update(e);
},
loadData() {
const resources = [
{name: "Resource 1", id: "R1"},
{name: "Resource 2", id: "R2"},
{name: "Resource 3", id: "R3"},
{name: "Resource 4", id: "R4"},
{name: "Resource 5", id: "R5"},
{name: "Resource 6", id: "R6"},
{name: "Resource 7", id: "R7"},
{name: "Resource 8", id: "R8"},
{name: "Resource 9", id: "R9"},
];
const events = [
{id: 1, start: "2026-08-05T00:00:00", end: "2026-08-10T00:00:00", text: "Event 1", resource: "R2"}
];
scheduler.update({resources, events});
}
};
app.loadData();
</script>
</body>
</html>