Vue Scheduler Customization
This guide covers the main customization layers in the Vue wrapper and when to use each one. Use it after you can render the wrapper and need application-specific UI or behavior.
Use this page with:
Choose The Right Customization Layer
Start with the lowest-cost option that solves the task:
- Use
configandtemplatesfor visual output and built-in behavior changes - Use
themeandlocalefor scheduler-wide skin and language switches - Return a Vue
VNodefromh()inside any template function -templates.event_text,templates.tooltip_text, scale/timeline cell templates, and columntemplate/label- whenever you need an interactive or composable Vue element instead of a string - Use
on<EventName>and@readyfor interaction rules and startup orchestration - Use
modalsfor delete-confirmation control - Use
customLightboxwhen edit UI must be application-specific and fits in a modal
Keep one data ownership model while customizing UI. If the scheduler edits data, make sure your Vue state strategy matches it.
Template-Driven Visual Customization
Use templates for event text, CSS classes, scale labels, and grid output.
<script setup lang="ts">
const templates = {
event_text: (_start: Date, _end: Date, event: Event) => `#${event.id}: ${event.text}`,
event_class: (_start: Date, _end: Date, event: Event) => (event.priority === "high" ? "event--high" : "")
};
</script>
<template>
<VueScheduler :events="events" :templates="templates" />
</template>
Use this when your changes map cleanly to native Scheduler template APIs.
Themes, Locales, And Vue Components Inside Templates
Use the theme and locale props for scheduler skin and language switches. Use h() to return Vue VNodes from any template function - both the timeline-side templates prop (event_text, tooltip_text, timeline_cell_content, ...). The wrapper mounts the result into the right place - the event, the scale cell, or the tooltip.
themeaccepts the built-in skin names (for example"terrace","dark")localeaccepts a locale code ("en","es","de","cn", ...) or a full locale object- Any template function can return either a plain string/HTML (the native Scheduler template shape) or
h(Component, props)for a Vue component - Wire interaction (
onToggle,onClick, ...) through Vue event props on the rendered component, the same way you would in a template
<script setup lang="ts">
import { h, ref } from "vue";
import { VueScheduler, defineSchedulerTemplates } from "@dhtmlx/trial-vue-scheduler";
import type { Marker, SchedulerConfig, VueSchedulerProps } from "@dhtmlx/trial-vue-scheduler";
import "@dhtmlx/trial-vue-scheduler/dist/vue-scheduler.css";
import EventTextBox from "../../components/EventTextBox.vue";
import { templateDate, templateEvents } from "../shared/demoData";
const theme = ref<"terrace" | "dark">("terrace");
const locale = ref<"en" | "es">("en");
const templates = defineSchedulerTemplates({
event_class: (_start: Date, _end: Date, event: any) => `templates-${event.classname || ""}`,
event_text: (_start: Date, _end: Date, event: any) => h(EventTextBox, { event })
});
const config: SchedulerConfig = {
first_hour: 6,
last_hour: 22,
hour_size_px: 60,
mark_now: false
};
function switchTheme() {
theme.value = theme.value === "terrace" ? "dark" : "terrace";
}
function switchLocale() {
locale.value = locale.value === "en" ? "es" : "en";
}
</script>
<template>
<div className="demo-panel">
<div className="demo-toolbar sample-actions">
<button @click="switchTheme">Switch Theme</button>
<button @click="switchLocale">Switch Locale</button>
</div>
<VueScheduler
:date="templateDate"
:events="templateEvents"
:templates="templates"
:config="config"
:theme="theme"
:locale="locale"
/>
</div>
</template>
Replace The Event Form (customLightbox)
Use customLightbox when the built-in lightbox is not enough and you need a Vue component for event editing.
<script setup lang="ts">
...
import CustomLightbox from "./CustomLightbox.vue";
</script>
<template>
<VueScheduler
:customLightbox="CustomLightbox"
/>
</template>
Your custom component receives:
dataonSave(event)onCancel()onDelete()schedulerInstance
<script setup lang="ts">
import { ref, watch } from "vue";
const props = defineProps<{
data: any;
onSave: (event: any) => void;
onCancel: () => void;
onDelete: () => void;
}>();
const description = ref(props.data?.text || "");
watch(
() => props.data,
next => {
description.value = next?.text || "";
},
{ immediate: true }
);
function save() {
props.onSave({ ...props.data, text: description.value });
}
</script>
<template>
<div className="modal-backdrop lightbox" data-cy="custom-lightbox" @click.self="props.onCancel">
<div className="custom-lightbox-dialog">
<div className="custom-lightbox-title">Edit Event</div>
<label className="custom-lightbox-label" htmlFor="event_text">Description</label>
<textarea id="event_text" v-model="description" className="custom-lightbox-textarea" autofocus />
<div className="custom-lightbox-actions">
<button data-cy="custom-lightbox-save" @click="save">Save</button>
<button @click="props.onCancel">Cancel</button>
<button @click="props.onDelete">Delete</button>
</div>
</div>
</div>
</template>
Replace The Lightbox With A Route
Use this pattern when the event editor needs its own page, deep-linkable URL, or layout that does not fit in a modal. Instead of supplying customLightbox, intercept lightbox events and route to a separate Vue Router view.
For a route-based editor, prevent the built-in lightbox with onBeforeLightbox(eventId), then navigate to your editor route.
function beforeLightbox(eventId: string | number) {
router.push(`/scheduler/editor/${eventId}`);
return false;
}
<VueScheduler :events="events" :onBeforeLightbox="beforeLightbox" />
Use a shared store or parent state to let the editor update the same events array passed into Scheduler.
For modal-style replacement, prefer customLightbox.
Custom Delete Confirmation Modals
Use modals to replace built-in event deletion confirmations.
const modals = {
onBeforeEventDelete: ({ event, callback }) => {
if (window.confirm(`Delete ${event.text}?`)) {
callback();
}
},
onRecurrenceConfirm: context => {
return context.options.includes("series") ? "series" : "occurrence";
}
};
<VueScheduler :events="events" :modals="modals" />
note:::
Enable the recurring plugin when customizing recurrence behavior.
:::
Timeline, Units, And Grid Views
Configure advanced views through the views prop. Check the whole list of timeline properties here
const views = {
timeline: {
name: "rooms",
render: "bar",
y_property: "room_id",
y_unit: [
{ key: 1, label: "Room 1" },
{ key: 2, label: "Room 2" }
],
x_unit: "hour",
x_step: 1,
x_size: 12
}
};
<VueScheduler
:events="events"
:plugins="{ timeline: true }"
:views="views"
view="rooms"
/>