Перейти к основному содержимому

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 config and templates for visual output and built-in behavior changes
  • Use theme and locale for scheduler-wide skin and language switches
  • Return a Vue VNode from h() inside any template function - templates.event_text, templates.tooltip_text, scale/timeline cell templates, and column template/label - whenever you need an interactive or composable Vue element instead of a string
  • Use on<EventName> and @ready for interaction rules and startup orchestration
  • Use modals for delete-confirmation control
  • Use customLightbox when 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.

  • theme accepts the built-in skin names (for example "terrace", "dark")
  • locale accepts 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:

  • data
  • onSave(event)
  • onCancel()
  • onDelete()
  • schedulerInstance
CustomLightbox.vue
<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"
/>

Continue With

Need help?
Got a question about the documentation? Reach out to our technical support team for help and guidance. For custom component solutions, visit the Services page.