DevExtreme v24.2 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.

Vue Scheduler - Overview

DevExtreme Vue Scheduler is a versatile scheduling component. Its main features include appointment editing, time zones support, vertical and horizontal orientation, and many more. You can use Vue syntax and techniques to instantiate and configure the Scheduler or handle its events. In addition, the component supports prop validation and templates that use named slots. Find out more about DevExtreme Vue components.

To get started with the DevExtreme Scheduler component, refer to the following tutorial for step-by-step instructions: Getting Started with Scheduler.

DevExtreme Accessibility Compliance
DevExtreme component libraries meet a variety of WCAG and Section 508 compliance standards. To assess this demo’s accessibility level, click the Run AXE® Validation button to launch the AXE® web accessibility evaluation tool.
All trademarks or registered trademarks are property of their respective owners. AXE® Terms of Use
The overall accessibility level of your application depends on the Scheduler features used.
Backend API
<template> <DxScheduler time-zone="America/Los_Angeles" :data-source="dataSource" :current-date="currentDate" :views="views" :groups="groups" :height="710" :show-all-day-panel="true" :first-day-of-week="1" :start-day-hour="8" :end-day-hour="18" current-view="month" data-cell-template="dataCellTemplate" resource-cell-template="resourceCellTemplate" > <DxResource :data-source="employees" :allow-multiple="false" label="Employee" field-expr="employeeID" /> <template #resourceCellTemplate="{ data: employee }"> <ResourceCell :employee="employee" /> </template> <template #dataCellTemplate="{ data: cellData }"> <DataCell :cell-data="cellData" /> </template> </DxScheduler> </template> <script setup lang="ts"> import { DxScheduler, DxResource } from 'devextreme-vue/scheduler'; import { employees, data } from './data.ts'; import DataCell from './DataCell.vue'; import ResourceCell from './ResourceCell.vue'; const groups = ['employeeID']; const views = ['month']; const currentDate = new Date(2021, 5, 2, 11, 30); const dataSource = data; </script> <style> .dx-scheduler-group-header, .dx-scheduler-date-table-cell { position: relative; } .dx-scheduler-group-header-content { padding-left: 8px; } .dx-color-scheme-light, .dx-color-scheme-carmine, .dx-color-scheme-softblue, .dx-color-scheme-blue-light, .dx-color-scheme-saas-light, .dx-color-scheme-lime-light, .dx-color-scheme-orange-light, .dx-color-scheme-purple-light, .dx-color-scheme-teal-light { --text-color-1: rgba(0, 0, 0, .6); --text-color-2: rgba(255, 255, 255, 1); --disabled-color: rgba(0, 0, 0, 0.38); --background-color-1: rgba(50, 134, 56, 1); --background-color-2: rgba(194, 81, 0, 1); } .dx-color-scheme-dark, .dx-color-scheme-darkviolet, .dx-color-scheme-darkmoon, .dx-color-scheme-blue-dark, .dx-color-scheme-saas-dark, .dx-color-scheme-lime-dark, .dx-color-scheme-orange-dark, .dx-color-scheme-purple-dark, .dx-color-scheme-teal-dark { --text-color-1: rgba(255, 255, 255, 1); --text-color-2: rgba(54, 54, 64, 1); --disabled-color: rgba(255, 255, 255, 0.38); --background-color-1: rgba(159, 213, 161, 1); --background-color-2: rgba(255, 181, 127, 1); } .dx-scheduler-header .dx-toolbar .dx-button, .dx-scheduler-header .dx-toolbar .dx-button .dx-icon { color: var(--text-color-1); } .dx-scheduler-date-table-other-month.dx-scheduler-date-table-cell { opacity: 1; color: var(--disabled-color) !important; } .dx-scheduler-work-space-month .dx-scheduler-date-table-cell { color: var(--text-color-1); } .dx-scheduler-work-space-month .dx-scheduler-appointment, .dx-scheduler-work-space-month .dx-scheduler-appointment.dx-state-focused { color: var(--text-color-2); line-height: 22px; } .dx-scheduler-work-space-month .dx-scheduler-appointment .dx-scheduler-appointment-content { padding-top: 0; } .dx-scheduler-date-table-cell .dx-template-wrapper { position: absolute; height: 100%; width: 100%; padding-right: 6px; } .dx-scheduler-appointment { color: rgba(255, 255, 255, 1); } </style>
<template> <div :class="markWeekEnd(cellData)" > <div :class="markTraining(cellData)"> {{ cellData.text }} </div> </div> </template> <script setup lang="ts"> withDefaults(defineProps<{ cellData?: any }>(), { cellData: () => {}, }); function markWeekEnd(cellData) { function isWeekEnd(date) { const day = date.getDay(); return day === 0 || day === 6; } const classObject = {}; classObject[`employee-${cellData.groups.employeeID}`] = true; classObject[`employee-weekend-${cellData.groups.employeeID}`] = isWeekEnd(cellData.startDate); return classObject; } function markTraining(cellData) { const classObject = { 'day-cell': true, }; classObject[ getCurrentTraining(cellData.startDate.getDate(), cellData.groups.employeeID) ] = true; return classObject; } function getCurrentTraining(date, employeeID) { const result = (date + employeeID) % 3; const currentTraining = `training-background-${result}`; return currentTraining; } </script> <style> .day-cell { width: 100%; height: 100%; background-position: center center; background-repeat: no-repeat; } .dx-scheduler-appointment { color: rgba(255, 255, 255, 1); } .employee-1 { background-color: rgba(55, 126, 58, 0.08); } .employee-2 { background-color: rgba(194, 81, 0, 0.08); } .employee-weekend-1 { background-color: rgba(55, 126, 58, 0.12); } .employee-weekend-2 { background-color: rgba(194, 81, 0, 0.12); } .training-background-0 { background-image: url("../../../../images/Scheduler/Overview/icon-abs.png"); } .training-background-1 { background-image: url("../../../../images/Scheduler/Overview/icon-step.png"); } .training-background-2 { background-image: url("../../../../images/Scheduler/Overview/icon-fitball.png"); } </style>
<template> <div> <div :style="'background:' + employee.color" class="name" > <h2>{{ employee.text }}</h2> </div> <div class="avatar" :title="employee.text"> <img :src="employee.data.avatar" :alt="`${employee.text} photo`"> </div> <div :style="'color:' + employee.color" class="info" > Age: {{ employee.data.age }} <br> <b>{{ employee.data.discipline }}</b> </div> </div> </template> <script setup lang="ts"> withDefaults(defineProps<{ employee?: any }>(), { employee: () => {}, }); </script> <style> .avatar { width: 124px; float: left; overflow: hidden; position: relative; height: 124px; border: 1px solid rgba(0, 0, 0, 0.24); border-radius: 50%; background-color: rgba(255, 255, 255, 1); } .avatar img { position: relative; width: 126px; height: 130px; object-fit: contain; } .avatar[title="John Heart"] img { top: 5px; left: 3px; } .avatar[title="Greta Sims"] img { top: 5px; left: -7px; } .name { position: absolute; bottom: 0; left: 0; width: 100%; } .name h2 { color: var(--text-color-2); font-size: 28px; text-align: left; padding: 0 0 0 170px; margin: 0; height: 40px; line-height: 40px; } .info { width: auto; text-align: left; height: 100%; font-size: 14px; line-height: 20px; font-weight: normal; padding: 25px 20px 25px 40px; color: #707070; } .dx-color-scheme-contrast .info { color: #fff; } </style>
window.exports = window.exports || {}; window.config = { transpiler: 'plugin-babel', meta: { '*.vue': { loader: 'vue-loader', }, '*.ts': { loader: 'demo-ts-loader', }, '*.svg': { loader: 'svg-loader', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, 'openai': { 'esModule': true, }, }, paths: { 'project:': '../../../../', 'npm:': 'https://cdn.jsdelivr.net/npm/', 'bundles:': '../../../../bundles/', 'externals:': '../../../../bundles/externals/', }, map: { 'vue': 'npm:vue@3.4.27/dist/vue.esm-browser.js', '@vue/shared': 'npm:@vue/shared@3.4.27/dist/shared.cjs.prod.js', 'vue-loader': 'npm:dx-systemjs-vue-browser@1.1.2/index.js', 'demo-ts-loader': 'project:utils/demo-ts-loader.js', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'svg-loader': 'project:utils/svg-loader.js', 'mitt': 'npm:mitt/dist/mitt.umd.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@3.4.4/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign', 'devextreme': 'npm:devextreme@24.2.7/cjs', 'devextreme-vue': 'npm:devextreme-vue@24.2.7/cjs', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.16/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.60/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.12', 'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js', 'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'devextreme-vue': { main: 'index.js', }, 'devextreme': { defaultExtension: 'js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/common/core/events/utils': { main: 'index', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.12/inferno/package.json', ], babelOptions: { sourceMaps: false, stage0: true, }, }; System.config(window.config);
export const employees = [{ text: 'John Heart', id: 1, color: 'var(--background-color-1)', avatar: '../../../../images/employees/19.png', age: 27, discipline: 'ABS, Fitball, StepFit', }, { text: 'Greta Sims', id: 2, color: 'var(--background-color-2)', avatar: '../../../../images/employees/31.png', age: 25, discipline: 'ABS, Fitball, StepFit', }]; export const data = [ { text: 'Helen', employeeID: 2, startDate: new Date('2021-06-01T16:30:00.000Z'), endDate: new Date('2021-06-01T18:30:00.000Z'), }, { text: 'Helen', employeeID: 2, startDate: new Date('2021-06-10T16:30:00.000Z'), endDate: new Date('2021-06-11T18:30:00.000Z'), }, { text: 'Alex', employeeID: 1, startDate: new Date('2021-06-02T16:30:00.000Z'), endDate: new Date('2021-06-02T18:30:00.000Z'), }, { text: 'Alex', employeeID: 1, startDate: new Date('2021-06-11T19:00:00.000Z'), endDate: new Date('2021-06-11T20:00:00.000Z'), }, { text: 'Alex', employeeID: 2, startDate: new Date('2021-06-16T16:30:00.000Z'), endDate: new Date('2021-06-16T18:30:00.000Z'), }, { text: 'Stan', employeeID: 1, startDate: new Date('2021-06-07T16:30:00.000Z'), endDate: new Date('2021-06-07T18:30:00.000Z'), }, { text: 'Stan', employeeID: 1, startDate: new Date('2021-06-28T16:30:00.000Z'), endDate: new Date('2021-06-28T18:30:00.000Z'), }, { text: 'Stan', employeeID: 1, startDate: new Date('2021-06-30T16:30:00.000Z'), endDate: new Date('2021-06-30T18:30:00.000Z'), }, { text: 'Rachel', employeeID: 2, startDate: new Date('2021-06-04T16:30:00.000Z'), endDate: new Date('2021-06-04T18:30:00.000Z'), }, { text: 'Rachel', employeeID: 2, startDate: new Date('2021-06-07T16:30:00.000Z'), endDate: new Date('2021-06-07T18:30:00.000Z'), }, { text: 'Rachel', employeeID: 1, startDate: new Date('2021-06-21T16:30:00.000Z'), endDate: new Date('2021-06-21T18:30:00.000Z'), }, { text: 'Kelly', employeeID: 2, startDate: new Date('2021-06-15T16:30:00.000Z'), endDate: new Date('2021-06-15T18:30:00.000Z'), }, { text: 'Kelly', employeeID: 2, startDate: new Date('2021-06-29T16:30:00.000Z'), endDate: new Date('2021-06-29T18:30:00.000Z'), }, ];
import { createApp } from 'vue'; import App from './App.vue'; createApp(App).mount('#app');
<!DOCTYPE html> <html lang="en"> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.2.7/css/dx.light.css" /> <script src="https://cdn.jsdelivr.net/npm/typescript@5.4.5/lib/typescript.js"></script> <script type="module"> import * as vueCompilerSFC from "https://cdn.jsdelivr.net/npm/@vue/compiler-sfc@3.4.27/dist/compiler-sfc.esm-browser.js"; window.vueCompilerSFC = vueCompilerSFC; </script> <script src="https://cdn.jsdelivr.net/npm/core-js@2.6.12/client/shim.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/systemjs@0.21.3/dist/system.js"></script> <script type="text/javascript" src="config.js"></script> <script type="text/javascript"> System.import("./index.ts"); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"> </div> </div> </body> </html>