DevExtreme v25.1 is now available.

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

Your search did not match any results.

React Scheduler - Toolbar

The DevExtreme Scheduler ships with a customizable toolbar UI element. You can populate the toolbar with predefined and custom items—in any display order. This demo adds the "today" predefined control and two DevExtreme components to the toolbar.

Backend API
import React, { useCallback, useMemo, useRef, useState } from 'react'; import { Scheduler, Resource, Toolbar, Item, type SchedulerRef, type SchedulerTypes } from 'devextreme-react/scheduler'; import { SelectBox, type SelectBoxTypes } from 'devextreme-react/select-box'; import { type DataSource } from 'devextreme-react/common/data'; import { assignees, schedulerDataSource, currentDate } from './data.ts'; const views: SchedulerTypes.ViewType[] = ['day', 'week', 'workWeek', 'month']; const selectBoxPlaceholder = 'Select Employee'; const inputAttr = { 'aria-label': selectBoxPlaceholder }; const MS_IN_HOUR = 60 * 1000; const App = () => { const schedulerRef = useRef<SchedulerRef>(null); const [assigneesFilterValue, setAssigneesFilterValue] = useState<number>(); const onAssigneesFilterChange = useCallback((event: SelectBoxTypes.ValueChangedEvent) => { const scheduler = schedulerRef.current?.instance?.(); if (!scheduler) { return; } const dataSource = scheduler.option('dataSource') as DataSource; const filter = event.value ? ['assigneeId', 'contains', event.value] : null; dataSource.filter(filter); scheduler.option('dataSource', dataSource); setAssigneesFilterValue(event.value); }, []); const onAppointmentAdd = useCallback(() => { const scheduler = schedulerRef.current?.instance?.(); if (!scheduler) { return; } const selected = scheduler.option('selectedCellData') ?? []; if (selected.length) { const firstSelected = selected[0]; const lastSelected = selected.at(-1); scheduler.showAppointmentPopup({ ...firstSelected.groups, allDay: firstSelected.allDay, startDate: new Date(firstSelected.startDateUTC), endDate: new Date(lastSelected.endDateUTC), }, true); return; } const currentDate = scheduler.option('currentDate'); const cellDuration = scheduler.option('cellDuration') as number; const cellDurationMs = cellDuration * MS_IN_HOUR; const currentTime = new Date(currentDate as Date).getTime(); const roundTime = Math.round(currentTime / cellDurationMs) * cellDurationMs; scheduler.showAppointmentPopup({ startDate: new Date(roundTime), endDate: new Date(roundTime + cellDurationMs), }, true); }, []); const toggleButtonOptions = useMemo(() => ({ icon: 'plus', text: 'New Appointment', stylingMode: 'outlined', type: 'normal', onClick() { onAppointmentAdd(); }, }), [onAppointmentAdd]); return ( <Scheduler timeZone="America/Los_Angeles" dataSource={schedulerDataSource} views={views} defaultCurrentView="workWeek" defaultCurrentDate={currentDate} startDayHour={9} endDayHour={19} height={600} ref={schedulerRef} > <Resource dataSource={assignees} allowMultiple={true} fieldExpr="assigneeId" label="Assignee" /> <Toolbar> <Item name="today" /> <Item name="dateNavigator" /> <Item location="before" locateInMenu="auto" widget="dxButton" options={toggleButtonOptions} /> <Item location="before" locateInMenu="auto"> <SelectBox placeholder={selectBoxPlaceholder} items={assignees} showClearButton={true} displayExpr="text" valueExpr="id" inputAttr={inputAttr} width={200} value={assigneesFilterValue} onValueChanged={onAssigneesFilterChange} /> </Item> <Item location="after" locateInMenu="auto" name="viewSwitcher" /> </Toolbar> </Scheduler> ); }; export default App;
import React, { useCallback, useMemo, useRef, useState, } from 'react'; import { Scheduler, Resource, Toolbar, Item, } from 'devextreme-react/scheduler'; import { SelectBox } from 'devextreme-react/select-box'; import { assignees, schedulerDataSource, currentDate } from './data.js'; const views = ['day', 'week', 'workWeek', 'month']; const selectBoxPlaceholder = 'Select Employee'; const inputAttr = { 'aria-label': selectBoxPlaceholder }; const MS_IN_HOUR = 60 * 1000; const App = () => { const schedulerRef = useRef(null); const [assigneesFilterValue, setAssigneesFilterValue] = useState(); const onAssigneesFilterChange = useCallback((event) => { const scheduler = schedulerRef.current?.instance?.(); if (!scheduler) { return; } const dataSource = scheduler.option('dataSource'); const filter = event.value ? ['assigneeId', 'contains', event.value] : null; dataSource.filter(filter); scheduler.option('dataSource', dataSource); setAssigneesFilterValue(event.value); }, []); const onAppointmentAdd = useCallback(() => { const scheduler = schedulerRef.current?.instance?.(); if (!scheduler) { return; } const selected = scheduler.option('selectedCellData') ?? []; if (selected.length) { const firstSelected = selected[0]; const lastSelected = selected.at(-1); scheduler.showAppointmentPopup( { ...firstSelected.groups, allDay: firstSelected.allDay, startDate: new Date(firstSelected.startDateUTC), endDate: new Date(lastSelected.endDateUTC), }, true, ); return; } const currentDate = scheduler.option('currentDate'); const cellDuration = scheduler.option('cellDuration'); const cellDurationMs = cellDuration * MS_IN_HOUR; const currentTime = new Date(currentDate).getTime(); const roundTime = Math.round(currentTime / cellDurationMs) * cellDurationMs; scheduler.showAppointmentPopup( { startDate: new Date(roundTime), endDate: new Date(roundTime + cellDurationMs), }, true, ); }, []); const toggleButtonOptions = useMemo( () => ({ icon: 'plus', text: 'New Appointment', stylingMode: 'outlined', type: 'normal', onClick() { onAppointmentAdd(); }, }), [onAppointmentAdd], ); return ( <Scheduler timeZone="America/Los_Angeles" dataSource={schedulerDataSource} views={views} defaultCurrentView="workWeek" defaultCurrentDate={currentDate} startDayHour={9} endDayHour={19} height={600} ref={schedulerRef} > <Resource dataSource={assignees} allowMultiple={true} fieldExpr="assigneeId" label="Assignee" /> <Toolbar> <Item name="today" /> <Item name="dateNavigator" /> <Item location="before" locateInMenu="auto" widget="dxButton" options={toggleButtonOptions} /> <Item location="before" locateInMenu="auto" > <SelectBox placeholder={selectBoxPlaceholder} items={assignees} showClearButton={true} displayExpr="text" valueExpr="id" inputAttr={inputAttr} width={200} value={assigneesFilterValue} onValueChanged={onAssigneesFilterChange} /> </Item> <Item location="after" locateInMenu="auto" name="viewSwitcher" /> </Toolbar> </Scheduler> ); }; export default App;
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.tsx'; ReactDOM.render( <App />, document.getElementById('app'), );
import { type SchedulerTypes } from 'devextreme-react/scheduler'; import { DataSource } from 'devextreme-react/common/data'; type Appointment = SchedulerTypes.Appointment & { assigneeId: number[]; }; export interface Assignee { text: string; id: number; } const ONE_MONTH_DAYS = 30; const addDays = (date, days) => new Date(new Date(date).setUTCDate(date.getUTCDate() + days)); const now = new Date(new Date().setUTCHours(0, 0, 0, 0)); const startOfTheWeek = addDays(now, -now.getUTCDay()); export const currentDate = addDays(now, ONE_MONTH_DAYS); const currentStartOfTheWeek = addDays(currentDate, -currentDate.getUTCDay()); const data: Appointment[] = [ { text: 'Website Re-Design Plan', assigneeId: [4], startDate: new Date(addDays(startOfTheWeek, 1).setUTCHours(16, 30)), endDate: new Date(addDays(startOfTheWeek, 1).setUTCHours(18, 30)), }, { text: 'Book Flights to San Fran for Sales Trip', assigneeId: [2], startDate: new Date(addDays(startOfTheWeek, 2).setUTCHours(19)), endDate: new Date(addDays(startOfTheWeek, 2).setUTCHours(20)), allDay: true, }, { text: 'Install New Router in Dev Room', assigneeId: [1], startDate: new Date(addDays(startOfTheWeek, 2).setUTCHours(21, 30)), endDate: new Date(addDays(startOfTheWeek, 2).setUTCHours(22, 30)), }, { text: 'Approve Personal Computer Upgrade Plan', assigneeId: [3], startDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(17)), endDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(18)), }, { text: 'Final Budget Review', assigneeId: [1], startDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(19)), endDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(20, 35)), }, { text: 'New Brochures', assigneeId: [4], startDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(21, 30)), endDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(22, 45)), }, { text: 'Install New Database', assigneeId: [2], startDate: new Date(addDays(startOfTheWeek, 4).setUTCHours(16, 45)), endDate: new Date(addDays(startOfTheWeek, 4).setUTCHours(18, 15)), }, { text: 'Approve New Online Marketing Strategy', assigneeId: [4], startDate: new Date(addDays(currentStartOfTheWeek, 1).setUTCHours(19)), endDate: new Date(addDays(currentStartOfTheWeek, 1).setUTCHours(21)), }, { text: 'Upgrade Personal Computers', assigneeId: [2], startDate: new Date(addDays(currentStartOfTheWeek, 1).setUTCHours(22, 15)), endDate: new Date(addDays(currentStartOfTheWeek, 1).setUTCHours(23, 30)), }, { text: 'Customer Workshop', assigneeId: [3], startDate: new Date(addDays(startOfTheWeek, 5).setUTCHours(18)), endDate: new Date(addDays(startOfTheWeek, 5).setUTCHours(19)), recurrenceRule: 'FREQ=WEEKLY;INTERVAL=1', }, { text: 'Prepare 2021 Marketing Plan', assigneeId: [1], startDate: new Date(addDays(currentStartOfTheWeek, 2).setUTCHours(18)), endDate: new Date(addDays(currentStartOfTheWeek, 2).setUTCHours(20, 30)), }, { text: 'Brochure Design Review', assigneeId: [4], startDate: new Date(addDays(startOfTheWeek, 5).setUTCHours(21)), endDate: new Date(addDays(startOfTheWeek, 5).setUTCHours(22, 30)), }, { text: 'Create Icons for Website', assigneeId: [3], startDate: new Date(addDays(currentStartOfTheWeek, 3).setUTCHours(17)), endDate: new Date(addDays(currentStartOfTheWeek, 3).setUTCHours(18, 30)), }, { text: 'Upgrade Server Hardware', assigneeId: [4], startDate: new Date(addDays(currentStartOfTheWeek, 2).setUTCHours(16)), endDate: new Date(addDays(currentStartOfTheWeek, 2).setUTCHours(17, 30)), }, { text: 'Submit New Website Design', assigneeId: [1], startDate: new Date(addDays(currentStartOfTheWeek, 5).setUTCHours(23, 30)), endDate: new Date(addDays(currentStartOfTheWeek, 6).setUTCHours(1)), }, { text: 'Launch New Website', assigneeId: [2], startDate: new Date(addDays(currentStartOfTheWeek, 4).setUTCHours(19)), endDate: new Date(addDays(currentStartOfTheWeek, 4).setUTCHours(21)), }, ]; export const schedulerDataSource = new DataSource(data); export const assignees: Assignee[] = [ { text: 'Samantha Bright', id: 1, }, { text: 'John Heart', id: 2, }, { text: 'Todd Hoffman', id: 3, }, { text: 'Sandra Johnson', id: 4, }, ];
window.exports = window.exports || {}; window.config = { transpiler: 'ts', typescriptOptions: { module: 'system', emitDecoratorMetadata: true, experimentalDecorators: true, jsx: 'react', }, meta: { 'react': { 'esModule': true, }, 'typescript': { 'exports': 'ts', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, 'openai': { 'esModule': true, }, }, paths: { 'npm:': 'https://cdn.jsdelivr.net/npm/', 'bundles:': '../../../../bundles/', 'externals:': '../../../../bundles/externals/', }, defaultExtension: 'js', map: { 'ts': 'npm:plugin-typescript@8.0.0/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.js', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'react': 'npm:react@17.0.2/umd/react.development.js', 'react-dom': 'npm:react-dom@17.0.2/umd/react-dom.development.js', 'prop-types': 'npm:prop-types/prop-types.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@25.1.3/cjs', 'devextreme-react': 'npm:devextreme-react@25.1.3/cjs', 'devextreme-quill': 'npm:devextreme-quill@1.7.3/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.19/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.62/dist/dx-gantt.js', 'inferno': 'npm:inferno@8.2.3/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@8.2.3/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', '@preact/signals-core': 'npm:@preact/signals-core@1.8.0/dist/signals-core.min.js', 'devextreme-cldr-data': 'npm:devextreme-cldr-data@1.0.3', // SystemJS plugins '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': { defaultExtension: 'js', }, 'devextreme-react': { main: 'index.js', }, 'devextreme-react/common': { main: 'index.js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/common/core/events/utils': { main: 'index', }, 'devextreme/localization/messages': { format: 'json', defaultExtension: 'json', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', ], babelOptions: { sourceMaps: false, stage0: true, react: true, }, }; System.config(window.config);
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render(<App />, document.getElementById('app'));
import { DataSource } from 'devextreme-react/common/data'; const ONE_MONTH_DAYS = 30; const addDays = (date, days) => new Date(new Date(date).setUTCDate(date.getUTCDate() + days)); const now = new Date(new Date().setUTCHours(0, 0, 0, 0)); const startOfTheWeek = addDays(now, -now.getUTCDay()); export const currentDate = addDays(now, ONE_MONTH_DAYS); const currentStartOfTheWeek = addDays(currentDate, -currentDate.getUTCDay()); const data = [ { text: 'Website Re-Design Plan', assigneeId: [4], startDate: new Date(addDays(startOfTheWeek, 1).setUTCHours(16, 30)), endDate: new Date(addDays(startOfTheWeek, 1).setUTCHours(18, 30)), }, { text: 'Book Flights to San Fran for Sales Trip', assigneeId: [2], startDate: new Date(addDays(startOfTheWeek, 2).setUTCHours(19)), endDate: new Date(addDays(startOfTheWeek, 2).setUTCHours(20)), allDay: true, }, { text: 'Install New Router in Dev Room', assigneeId: [1], startDate: new Date(addDays(startOfTheWeek, 2).setUTCHours(21, 30)), endDate: new Date(addDays(startOfTheWeek, 2).setUTCHours(22, 30)), }, { text: 'Approve Personal Computer Upgrade Plan', assigneeId: [3], startDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(17)), endDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(18)), }, { text: 'Final Budget Review', assigneeId: [1], startDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(19)), endDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(20, 35)), }, { text: 'New Brochures', assigneeId: [4], startDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(21, 30)), endDate: new Date(addDays(startOfTheWeek, 3).setUTCHours(22, 45)), }, { text: 'Install New Database', assigneeId: [2], startDate: new Date(addDays(startOfTheWeek, 4).setUTCHours(16, 45)), endDate: new Date(addDays(startOfTheWeek, 4).setUTCHours(18, 15)), }, { text: 'Approve New Online Marketing Strategy', assigneeId: [4], startDate: new Date(addDays(currentStartOfTheWeek, 1).setUTCHours(19)), endDate: new Date(addDays(currentStartOfTheWeek, 1).setUTCHours(21)), }, { text: 'Upgrade Personal Computers', assigneeId: [2], startDate: new Date(addDays(currentStartOfTheWeek, 1).setUTCHours(22, 15)), endDate: new Date(addDays(currentStartOfTheWeek, 1).setUTCHours(23, 30)), }, { text: 'Customer Workshop', assigneeId: [3], startDate: new Date(addDays(startOfTheWeek, 5).setUTCHours(18)), endDate: new Date(addDays(startOfTheWeek, 5).setUTCHours(19)), recurrenceRule: 'FREQ=WEEKLY;INTERVAL=1', }, { text: 'Prepare 2021 Marketing Plan', assigneeId: [1], startDate: new Date(addDays(currentStartOfTheWeek, 2).setUTCHours(18)), endDate: new Date(addDays(currentStartOfTheWeek, 2).setUTCHours(20, 30)), }, { text: 'Brochure Design Review', assigneeId: [4], startDate: new Date(addDays(startOfTheWeek, 5).setUTCHours(21)), endDate: new Date(addDays(startOfTheWeek, 5).setUTCHours(22, 30)), }, { text: 'Create Icons for Website', assigneeId: [3], startDate: new Date(addDays(currentStartOfTheWeek, 3).setUTCHours(17)), endDate: new Date(addDays(currentStartOfTheWeek, 3).setUTCHours(18, 30)), }, { text: 'Upgrade Server Hardware', assigneeId: [4], startDate: new Date(addDays(currentStartOfTheWeek, 2).setUTCHours(16)), endDate: new Date(addDays(currentStartOfTheWeek, 2).setUTCHours(17, 30)), }, { text: 'Submit New Website Design', assigneeId: [1], startDate: new Date(addDays(currentStartOfTheWeek, 5).setUTCHours(23, 30)), endDate: new Date(addDays(currentStartOfTheWeek, 6).setUTCHours(1)), }, { text: 'Launch New Website', assigneeId: [2], startDate: new Date(addDays(currentStartOfTheWeek, 4).setUTCHours(19)), endDate: new Date(addDays(currentStartOfTheWeek, 4).setUTCHours(21)), }, ]; export const schedulerDataSource = new DataSource(data); export const assignees = [ { text: 'Samantha Bright', id: 1, }, { text: 'John Heart', id: 2, }, { text: 'Todd Hoffman', id: 3, }, { text: 'Sandra Johnson', id: 4, }, ];
<!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/25.1.3/css/dx.light.css" /> <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.tsx"); </script> <link rel="stylesheet" type="text/css" href="styles.css" /> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"></div> </div> </body> </html>

To customize the Scheduler toolbar in your DevExtreme-powered app, add items to the toolbar.items[] array. DevExtreme Scheduler supports the following toolbar item types:

  • Predefined Controls

    • "dateNavigator"
      Displays a ButtonGroup component with next/previous buttons and a date interval button that invokes a dropdown calendar. Define options.items to customize the control. You can add new buttons, and specify button availability/order.
    • "viewSwitcher"
      Switches between view types (day, week, month, and others).
    • "today"
      A "Today" button (navigates to the current date).
  • DevExtreme Components
    You can configure a DevExtreme component within a toolbar item element. In this demo, we extended the toolbar with a Button and SelectBox.

  • Custom Controls
    Specify items[].render or component to implement custom controls.

The default Scheduler toolbar displays "dateNavigator" and "viewSwitcher" predefined controls.