Skip to content

Slots, Hours, and Markers

Create preview customization affects empty-slot hover labels and the drag-create range preview.

grid.eventScheduler = {
view: 'week',
weekStartDate: '2026-06-08',
editable: true,
allowCreate: true,
customization: {
createPreview: {
hoverTimeProperties: ({ startDateTime }) => ({
class: 'create-hover-slot',
'data-hover-start': startDateTime,
}),
createRangeTemplate: ({ title, startLabel, endLabel, durationLabel, resource }) =>
`${title} for ${resource?.name ?? 'Unassigned'}: ${startLabel}-${endLabel} (${durationLabel})`,
createRangeProperties: ({ durationMinutes }) => ({
class: durationMinutes >= 240 ? 'create-range--long' : 'create-range--short',
}),
},
},
};

Use hoverTimeProperties for attributes and styling on the slot while the pointer is over a creatable time. Use createRangeTemplate and createRangeProperties for the range ghost shown during drag-create interactions.

Empty slots are a primary extension point for booking, staffing, room planning, maintenance windows, pricing, capacity, and availability workflows. Use direct slot hooks when a product needs custom empty-cell content or behavior without replacing event bars.

HookPurpose
slotTemplateRenders custom content inside empty week or resource-timeline slots. Occupied slots keep their event bars.
slotPropertiesAdds classes, styles, attributes, data fields, or event handlers to scheduler slot cells.
slotTooltipOverrides the native tooltip for disabled, closed, priced, or capacity-based slots.
onSlotClickRuns custom click behavior before built-in editor-open behavior.
onSlotDoubleClickRuns custom double-click behavior for immediate create or custom workflows.
onSlotContextMenuReceives the resolved slot when the scheduler context menu opens.
isSlotDisabledMarks slots as disabled and blocks built-in create/editor behavior.
isSlotSelectableMarks slots as non-selectable for create/selection UX.
grid.eventScheduler = {
view: 'resourceTimeline',
weekStartDate: '2026-06-08',
editable: true,
allowCreate: true,
slotTemplate: (h, context) =>
h('span', { class: 'booking-slot-capacity' }, [
context.disabled ? 'Closed' : `${getCapacity(context)} seats`,
]),
slotProperties: (context) => ({
class: [
context.disabled ? 'booking-slot--closed' : '',
!context.selectable ? 'booking-slot--invalid' : '',
context.segmentCount > 0 ? 'booking-slot--busy' : 'booking-slot--open',
].filter(Boolean).join(' '),
style: {
'--booking-slot-capacity': getCapacity(context),
},
'data-booking-slot': context.startDateTime,
}),
slotTooltip: (context) =>
context.disabled ? 'Outside working hours' : `Available from ${context.startDateTime}`,
isSlotDisabled: (context) => isClosedForBusiness(context),
isSlotSelectable: (context) => !hasBlockedAvailability(context),
onSlotClick: (context, event) => {
if (context.disabled) {
event.preventDefault();
showClosedSlotPopover(context);
}
},
onSlotDoubleClick: (context) => {
if (!context.disabled) createBookingImmediately(context);
},
onSlotContextMenu: (context) => {
trackSlotMenuOpened(context);
},
contextMenu: {
enabled: true,
hiddenItems: {
create: true,
'assign-open': true,
},
items: ({ target, slot }) => target === 'slot' && slot
? [
{ name: 'Create booking', action: () => createBookingImmediately(slot) },
{ name: 'Block this time', action: () => blockSlot(slot) },
]
: [],
},
};

slotTemplate is intentionally limited to empty cells so products can customize available space without removing visible event bars. Use customization.cells.dayTemplate or customization.cells.timelineTemplate only when the whole scheduler body cell, including event rendering, should be replaced. Use isSlotDisabled and isSlotSelectable with allowCreate or conflict rules when closed hours should block create, drag, paste, and editor flows.

Use working and closed-hour APIs when availability is part of the scheduler contract: business hours, weekends, holidays, lunch breaks, maintenance windows, or capacity holds. These hooks build on the existing nonWorkingTime, calendars, availability data, and conflict rules.

ConfigPurpose
workingHoursDefines global or per-weekday working ranges. Use false in byDay to close a weekday.
closedHoursDefines closed ranges such as lunch, maintenance, holidays, or blocked planning windows.
availabilityRulesApplies product-specific availability rules from slot context.
closedSlotTemplateRenders custom content inside closed slots.
closedSlotPropertiesAdds classes, styles, attributes, data fields, or event handlers to closed slots.
closedSlotTooltipOverrides the native tooltip/title for closed slots.
isTimeSlotAvailableBlocks built-in create/editor behavior when it returns false.

Use workingHours for global business hours, workingHours.byDay for weekday-specific hours or closed weekends, closedHours for explicit closed ranges such as lunch or maintenance, and date-specific closedHours entries for holidays. Closed slots can be styled with closedSlotProperties, replaced with closedSlotTemplate, and explained through closedSlotTooltip.

grid.eventScheduler = {
view: 'week',
weekStartDate: '2026-06-08',
editable: true,
allowCreate: true,
workingHours: {
byDay: {
1: { start: '08:00', end: '18:00' },
2: { start: '08:00', end: '18:00' },
3: { start: '08:00', end: '18:00' },
4: { start: '08:00', end: '18:00' },
5: { start: '08:00', end: '16:00' },
0: false,
6: false,
},
},
closedHours: [
{
id: 'lunch',
days: [1, 2, 3, 4, 5],
ranges: { start: '12:00', end: '13:00' },
title: 'Closed',
reason: 'Lunch break',
className: 'planner-slot--lunch',
},
{
id: 'maintenance',
dates: ['2026-06-10'],
ranges: { start: '15:00', end: '17:00' },
reason: 'Maintenance window',
className: 'planner-slot--maintenance',
},
],
availabilityRules: ({ date, startMinutes }) =>
date === '2026-06-12' && startMinutes >= 14 * 60
? { available: false, reason: 'Capacity hold', className: 'planner-slot--held' }
: undefined,
isTimeSlotAvailable: ({ date, slotIndex }) =>
!isCompanyHoliday(date) && slotIndex !== 0,
closedSlotProperties: ({ availabilityKind, reason }) => ({
class: `planner-slot--closed planner-slot--${availabilityKind}`,
style: {
'--planner-closed-opacity': reason === 'Lunch break' ? 0.6 : 0.85,
},
}),
closedSlotTooltip: ({ title, reason }) =>
[title, reason].filter(Boolean).join(' - '),
closedSlotTemplate: (h, { reason }) =>
h('span', { class: 'planner-slot__closed-label' }, reason ?? 'Closed'),
};

Closed-slot context extends normal slot context with available, availabilityKind, availabilityId, title, and reason. Built-in create/editor behavior is blocked when isTimeSlotAvailable returns false, when closedHours/availabilityRules mark the slot unavailable, or when isSlotDisabled / isSlotSelectable deny the slot. For resource-specific calendars, remote availability, and holidays, continue using calendars and eventSchedulerAvailability; the closed-slot hooks style those states too.

The current-time marker can use the built-in red line and badge, or it can be replaced by product-specific marker content. Week-style views render a horizontal marker on the active date. Resource timeline views render a vertical marker in the active timeline slot.

ConfigPurpose
showCurrentTimeMarkerSimple show/hide alias.
currentTimeMarkerDetailed marker config, including fixed dateTime for deterministic demos/tests.
currentTimeUpdateIntervalLive refresh interval in milliseconds. Defaults to 60000; use 0 to disable automatic live refresh.
currentTimeLabelFormatterFormats the marker label, such as 12:26, Now, or a localized time.
currentTimeMarkerTemplateReplaces marker content in week and resource timeline cells.
currentTimeMarkerPropertiesAdds classes, styles, attributes, data fields, or event handlers to the marker cell.
grid.eventScheduler = {
view: 'week',
weekStartDate: '2026-06-08',
showCurrentTimeMarker: true,
currentTimeUpdateInterval: 60_000,
currentTimeLabelFormatter: ({ dateTime }) =>
new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: '2-digit',
}).format(new Date(dateTime)),
currentTimeMarkerProperties: ({ orientation }) => ({
class: orientation === 'horizontal'
? 'planner-now-marker planner-now-marker--horizontal'
: 'planner-now-marker planner-now-marker--vertical',
style: {
'--event-scheduler-current-time-color': '#dc2626',
'--planner-now-marker-thickness': '2px',
},
}),
currentTimeMarkerTemplate: (h, context) =>
h('span', { class: 'planner-now-marker__label' }, context.label),
};

Marker context includes view, date, dayIndex, slotIndex, startMinutes, endMinutes, dateTime, label, position, orientation, and, when available, row, resourceId, and resource. The marker is hidden when disabled, outside the visible date range, or outside the visible time range. Use currentTimeMarker: { dateTime } when the marker should point at a fixed instant rather than live now.