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
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-defaultUsage
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(
Temporal.PlainDateTime.from('2025-03-07T08:00'),
Temporal.PlainDateTime.from('2025-03-07T19: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(
Temporal.PlainDate.from('2025-03-05'),
Temporal.PlainDate.from('2025-03-20')
)
const resources = [
{
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({
resources,
translations: mergeLocales(
translations,
modalTranslations,
resourceViewTranslations
),
events: [
{
id: 1,
title: 'Event 1',
start: Temporal.ZonedDateTime.from('2024-05-11T14:00:00+09:00[Asia/Tokyo]'),
end: Temporal.ZonedDateTime.from('2024-05-11T17:00:00+09:00[Asia/Tokyo]'),
resourceId: '1'
},
{
id: 2,
title: 'Event 2',
start: Temporal.ZonedDateTime.from('2024-05-11T14:00:00+09:00[Asia/Tokyo]'),
end: Temporal.ZonedDateTime.from('2024-05-11T16:00:00+09:00[Asia/Tokyo]'),
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>
// 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>
// can be used to set the day boundaries of the hourly view
// start and end can be integers between 0 and 23, representing the hour of the day
dayBoundaries: Signal<{ start: number, end: number }>
// should infinite scroll be enabled
infiniteScroll: Signal<boolean>
// callback that runs when the user scrolls the hourly view
onLazyLoadDate?: (dates: Temporal.PlainDate[]) => void
// Can be used to debounce the lazy load date callback with any number of milliseconds. Defaults to 0.
lazyLoadDateDebounce: Signal<number>
// callback that runs when the user scrolls the daily view
onLazyLoadMonth?: (dates: Temporal.PlainDate[]) => void
// callback for detecting clicks in the hourly view
onClickDateTime: Signal<(datetime: Temporal.ZonedDateTime, resourceId: string) => void>
// callback for detecting double clicks in the hourly view
onDoubleClickDateTime: Signal<(datetime: Temporal.ZonedDateTime, resourceId: string) => void>
// callback for detecting clicks in the daily view
onClickDate: Signal<(date: Temporal.PlainDate, resourceId: string) => void>
// callback for detecting double clicks in the daily view
onDoubleClickDate: Signal<(date: Temporal.PlainDate, 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<Temporal.PlainDateTime[] | undefined>
// Can be used to set the initially displayed days of the daily view
initialDays: Signal<Temporal.PlainDate[] | 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>
// Dictates whether the current day should be highlighted in both daily and hourly view. Defaults to true.
highlightToday: signal(false),
// Can be used to configure the format of the day names in daily view. Defaults to 'short'. Disable day names by setting to false.
dayNameFormat: Signal<false | 'short' | 'long' | 'narrow' | ((date: Temporal.PlainDate, locale: string) => string)>
}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