Skip to Content
v3is coming! Temporal API, timezones, and more đŸ„ł
DocsCalendar⭐ Resource scheduler

Resource Scheduler

A view for displaying resources (people, rooms, equipment etc.) in a time grid.

This is a premium feature which requires an active license to be used. Learn more at Schedule-X premium.

Features & demo

  • Infinite scroll & lazy loading
  • Drag & drop
  • Resizing events
  • Interactive modal for adding, editing or deleting events
  • Outlook-inspired Scheduling assistant

Go to Demo


2. Installation

2.1 Set up premium auth (only once)

Follow the instructions for setting up an .npmrc

2.2 Install

npm install @sx-premium/resource-scheduler @schedule-x/calendar @schedule-x/translations @schedule-x/theme-default

Usage

import { createCalendar } from '@schedule-x/calendar' import { createEventsServicePlugin } from "@schedule-x/events-service"; import { createInteractiveEventModal, translations as modalTranslations } from "@sx-premium/interactive-event-modal"; import { createHourlyView, createDailyView, createConfig, translations as resourceViewTranslations, TimeUnits } from "@sx-premium/resource-scheduler"; import { translations, mergeLocales } from '@schedule-x/translations' import { signal } from "@preact/signals"; import '@sx-premium/resource-scheduler/index.css' import '@sx-premium/interactive-event-modal/index.css' import '@schedule-x/theme-default/dist/time-picker.css' const resourceConfig = createConfig(); const hourlyView = createHourlyView(resourceConfig); const dailyView = createDailyView(resourceConfig); // enable or disable drag and drop, resizing resourceConfig.resize.value = true resourceConfig.dragAndDrop.value = true // optionally set the initially displayed columns of the hourly view // can be combined with `infiniteScroll.value = false` to achieve a scheduler with fixed columns resourceConfig.initialHours.value = new TimeUnits().getDayHoursBetween( '2025-03-07 08:00', '2025-03-08 02:00' ) // optionally set the initially displayed days of the daily view // can be combined with `infiniteScroll.value = false` to achieve a scheduler with fixed columns resourceConfig.initialDays.value = new TimeUnits().getDaysBetween( '2025-03-05', '2025-03-20' ) resourceConfig.resources.value = [ { label: 'Room 100', id: '1', resources: [ { label: 'Room 100A', id: '1.1', isOpen: signal(false), resources: [ { label: 'Room 100A1', id: '1.1.1', colorName: 'room-100A1', lightColors: { main: '#1c7df9', container: '#d2e7ff', onContainer: '#002859', }, }, { label: 'Room 100A2', id: '1.1.2', }, { label: 'Room 100A3', id: '1.1.3', } ], }, { label: 'Room 100B', id: '1.2', isOpen: signal(false), resources: [ { label: 'Room 100B1', id: '1.2.1', }, { label: 'Room 100B2', id: '1.2.2', }, { label: 'Room 100B3', id: '1.2.3', } ] } ] }, { labelHTML: '<span>Room <strong>101</strong></span>', id: '2', colorName: 'room-101', lightColors: { main: '#1c7df9', container: '#d2e7ff', onContainer: '#002859' }, darkColors: { main: '#c0dfff', onContainer: '#dee6ff', container: '#426aa2' } } ] const eventsService = createEventsServicePlugin() const interactiveEventModal = createInteractiveEventModal({ eventsService, onAddEvent: (event) => { console.log('Event added', event) }, fields: { title: {}, resourceId: {} } }) const calendar = createCalendar({ translations: mergeLocales( translations, modalTranslations, resourceViewTranslations ), events: [ { id: 1, title: 'Event 1', start: '2024-05-11 14:00', end: '2024-05-11 17:00', resourceId: '1' }, { id: 2, title: 'Event 2', start: '2024-05-11 14:00', end: '2024-05-11 16:00', resourceId: '2' } ], views: [hourlyView, dailyView], plugins: [ eventsService, interactiveEventModal ] }) calendar.render(document.getElementById('your-calendar-wrapper'))

API

ResourceSchedulerConfig

Signal is a reactive variable which holds a value property. This enables you to reactively update the value of your config variables. So if you wish to override the default hourWidth of the hourly view, you can do so by setting config.hourWidth.value = 100.

export type ResourceViewConfig = { // width of a column in the hourly view hourWidth: Signal<number> // width of a column in the daily view dayWidth: Signal<number> // list of resources you want to display resources: Signal<Resource[]> // height of a resource row resourceHeight: Signal<number> // height of an event eventHeight: Signal<number> // should drag and drop be enabled dragAndDrop: Signal<boolean> // should resizing be enabled resize: Signal<boolean> // should infinite scroll be enabled infiniteScroll: Signal<boolean> // callback that runs when the user scrolls the hourly view onLazyLoadDate?: (dates: Date[]) => void // callback that runs when the user scrolls the daily view onLazyLoadMonth?: (dates: Date[]) => void // callback for detecting clicks in the hourly view onClickDateTime: Signal<(datetime: string, resourceId: string) => void> // callback for detecting double clicks in the hourly view onDoubleClickDateTime: Signal<(datetime: string, resourceId: string) => void> // callback for detecting clicks in the daily view onClickDate: Signal<(date: string, resourceId: string) => void> // callback for detecting double clicks in the daily view onDoubleClickDate: Signal<(date: string, resourceId: string) => void> // callback for detecting clicks on a resource onClickResource: Signal<(resourceId: string) => void> // Can be used to set the initially displayed hours of the hourly view initialHours: Signal<Date[] | undefined> // Can be used to set the initially displayed days of the daily view initialDays: Signal<Date[] | undefined> // Can be used to configure the snapping duration of drag & drop dragSnapping: Signal<15 | 30 | 60> // Can be used to configure the snapping duration of resizing resizeSnapping: Signal<15 | 30 | 60> }

Resource

export type Resource = { label?: string labelHTML?: string id: string colorName?: string lightColors?: ColorDefinition darkColors?: ColorDefinition resources?: Resource[] isOpen?: Signal<boolean> }

ColorDefinition

export type ColorDefinition = { main: string container: string onContainer: string }

Changelog

See changelog page.

Examples

These can be added on request. Please let us know if you need an example for a specific framework.

Last updated on

We use cookies for marketing purposes. By clicking "Accept", you consent to the use of all cookies. If you decline, we will only use functional cookies. You can read more about our cookie policy here.