Slots, Hours, and Markers
Create previews
Section titled “Create previews”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 slot customization
Section titled “Empty slot customization”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.
| Hook | Purpose |
| --- | --- |
| slotTemplate | Renders custom content inside empty week or resource-timeline slots. Occupied slots keep their event bars. |
| slotProperties | Adds classes, styles, attributes, data fields, or event handlers to scheduler slot cells. |
| slotTooltip | Overrides the native tooltip for disabled, closed, priced, or capacity-based slots. |
| onSlotClick | Runs custom click behavior before built-in editor-open behavior. |
| onSlotDoubleClick | Runs custom double-click behavior for immediate create or custom workflows. |
| onSlotContextMenu | Receives the resolved slot when the scheduler context menu opens. |
| isSlotDisabled | Marks slots as disabled and blocks built-in create/editor behavior. |
| isSlotSelectable | Marks 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.
Working and closed hours
Section titled “Working and closed hours”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.
| Config | Purpose |
| --- | --- |
| workingHours | Defines global or per-weekday working ranges. Use false in byDay to close a weekday. |
| closedHours | Defines closed ranges such as lunch, maintenance, holidays, or blocked planning windows. |
| availabilityRules | Applies product-specific availability rules from slot context. |
| closedSlotTemplate | Renders custom content inside closed slots. |
| closedSlotProperties | Adds classes, styles, attributes, data fields, or event handlers to closed slots. |
| closedSlotTooltip | Overrides the native tooltip/title for closed slots. |
| isTimeSlotAvailable | Blocks 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.
Current time marker
Section titled “Current time marker”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.
| Config | Purpose |
| --- | --- |
| showCurrentTimeMarker | Simple show/hide alias. |
| currentTimeMarker | Detailed marker config, including fixed dateTime for deterministic demos/tests. |
| currentTimeUpdateInterval | Live refresh interval in milliseconds. Defaults to 60000; use 0 to disable automatic live refresh. |
| currentTimeLabelFormatter | Formats the marker label, such as 12:26, Now, or a localized time. |
| currentTimeMarkerTemplate | Replaces marker content in week and resource timeline cells. |
| currentTimeMarkerProperties | Adds 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.