Skip to content

Layout, Headers, and Cells

Use the grouped customization API when you need precise control over generated scheduler surfaces.

grid.eventScheduler = {
view: 'week',
weekStartDate: '2026-06-08',
customization: {
columnSizes: {
week: {
timeColumnSize: 96,
dayColumnSize: 220,
},
resourceTimeline: {
resourceColumnSize: 260,
timelineColumnSize: 144,
},
},
headers: {
dayTemplate: (h, context) =>
h('span', { class: 'scheduler-day-header' }, context.defaultLabel),
dayProperties: (context) => ({
class: context.today ? 'scheduler-day-header--brand-today' : '',
'data-scheduler-date': context.date,
}),
groupTemplate: (h, context) =>
h('strong', { class: 'scheduler-range-header' }, context.defaultLabel),
},
cells: {
resourceProperties: ({ resource }) => ({
'data-resource-role': resource?.role,
}),
timelineProperties: ({ date, slotIndex }) => ({
class: 'scheduler-timeline-slot',
'data-scheduler-slot-key': `${date}:${slotIndex}`,
}),
},
events: {
properties: ({ event }) => ({
'data-event-status': event.status,
}),
content: (h, { event, resource }) =>
h('span', { class: 'scheduler-event-title' }, [
h('strong', {}, event.title),
h('small', {}, resource?.name ?? 'Unassigned'),
]),
badge: (h, context) =>
h('span', {
class: `scheduler-event-chip scheduler-event-chip--${context.kind}`,
}, context.label),
resizeHandle: (h, context) =>
h('span', {
class: `scheduler-event-resize scheduler-event-resize--${context.edge}`,
}),
},
createPreview: {
createRangeTemplate: (context) =>
`${context.title}: ${context.startLabel}-${context.endLabel}`,
createRangeProperties: () => ({ class: 'scheduler-create-preview' }),
},
conflicts: {
className: ({ severity }) => `scheduler-conflict scheduler-conflict--${severity}`,
indicator: (h, context) =>
h('span', { class: 'scheduler-conflict-badge' }, context.severity),
tooltip: ({ label }) => `Review before saving: ${label}`,
},
emptyState: {
template: ({ kind, label }) => `${kind}: ${label}`,
properties: ({ kind }) => ({
class: `scheduler-state scheduler-state--${kind}`,
}),
},
},
};

Template hooks receive RevoGrid’s h helper and a scheduler context object. Return a string, a VNode, null, or undefined. Returning null or undefined keeps the built-in section. Property hooks return attributes, class, style, or data attributes for the target element.

Custom properties are merged with built-in scheduler properties. Built-in interaction handlers and scheduler data attributes remain in place, so custom hooks should not attach drag, resize, selection, or mutation behavior directly.

customization.columnSizes controls scheduler-owned column widths by view. These values are resolved before legacy top-level size props such as timeColumnSize, dayColumnSize, resourceColumnSize, and timelineColumnSize.

grid.eventScheduler = {
view: 'resourceTimeline',
weekStartDate: '2026-06-08',
customization: {
columnSizes: {
week: {
timeColumnSize: 88,
dayColumnSize: 180,
},
resourceTimeline: {
resourceColumnSize: 280,
timelineColumnSize: 120,
},
},
},
};

Use week sizes for day, week, and month style calendar grids. Use resource timeline sizes when the first column is the pinned resource column and the remaining columns are timeline slots.

Header customization targets the generated scheduler columns. For day headers, use the direct week-scheduler hooks when you only need day-header customization. Use customization.headers when you need to customize every generated header type.

Direct day-header hooks:

HookSurface
dayHeaderFormatterFormats the built-in day header label.
dayHeaderTemplateReplaces the day header content.
dayHeaderPropertiesAdds classes, styles, attributes, data fields, or event handlers to day headers.
grid.eventScheduler = {
view: 'week',
weekStartDate: '2026-06-08',
dayHeaderFormatter: (date) =>
date.toLocaleDateString('en-US', {
weekday: 'short',
month: 'short',
day: 'numeric',
timeZone: 'UTC',
}),
dayHeaderTemplate: (h, context) =>
h('span', { class: 'planner-day-header' }, [
h('span', { class: 'planner-day-header__label' }, context.defaultLabel),
context.today ? h('span', { class: 'planner-day-header__badge' }, 'Today') : null,
context.holiday ? h('span', { class: 'planner-day-header__holiday' }, context.holidayLabel) : null,
h('span', { class: 'planner-day-header__count' }, `${context.eventCount ?? 0} events`),
]),
dayHeaderProperties: (context) => ({
class: [
context.today ? 'planner-day-header--today' : '',
context.weekend ? 'planner-day-header--weekend' : '',
context.holiday ? 'planner-day-header--holiday' : '',
].filter(Boolean).join(' '),
style: {
'--planner-day-event-count': context.eventCount ?? 0,
...(context.holiday ? { '--planner-day-state': 'holiday' } : {}),
},
'data-planner-day': context.date,
}),
};

Day header context includes defaultLabel, date, dayIndex, eventCount, today, weekend, holiday, and holidayLabel. Holiday state is date-level: it comes from the primary scheduler calendar or global kind: 'holiday' availability entries. Resource-specific holidays stay on the scheduler body cells.

customization.headers.dayTemplate takes precedence over dayHeaderTemplate when both are provided. This lets applications keep older grouped customization config while adding direct day-header hooks where convenient.

Grouped header customization has one template hook and one matching properties hook per generated header section.

HookSurface
timeTemplate / timePropertiesPinned time header in day/week/month style views.
resourceTemplate / resourcePropertiesPinned resource header in resource timeline views.
dayTemplate / dayPropertiesDay header cells.
timelineTemplate / timelinePropertiesResource timeline slot headers.
groupTemplate / groupPropertiesGrouped range/day/timeline headers when column grouping is enabled.
grid.eventScheduler = {
view: 'week',
weekStartDate: '2026-06-08',
customization: {
headers: {
dayTemplate: (h, context) =>
h('span', { class: 'brand-day-header' }, [
h('strong', {}, context.defaultLabel),
context.today ? h('small', {}, 'Today') : null,
context.holiday ? h('small', {}, context.holidayLabel) : null,
context.eventCount ? h('small', {}, `${context.eventCount} events`) : null,
]),
dayProperties: (context) => ({
class: [
context.today ? 'brand-day-header--today' : '',
context.weekend ? 'brand-day-header--weekend' : '',
context.holiday ? 'brand-day-header--holiday' : '',
],
'data-brand-date': context.date,
}),
},
},
};

Header contexts include the active view, the default label, date or slot fields where relevant, event counts, today/weekend/holiday flags, holiday labels, and group kind for grouped headers.

Cell customization targets the scheduler body cells. Use property hooks when you only need classes, styles, or test/data attributes. Use templates when the default cell body should be replaced.

Use the direct time-axis hooks when the product only needs to control the pinned time column in day, week, or month-style views.

ConfigPurpose
timeLabelFormatterFormats built-in time text such as 06:00, 6 AM, or 6:00.
timeLabelTemplateReplaces the pinned time-label cell content.
timeRowPropertiesAdds classes, styles, attributes, data fields, or event handlers to time-label cells.
timeRangeSets the visible start/end time and hides time outside that range.
slotMinutesSets row granularity with a 15-minute minimum, for example 15, 30, or 60. When snapMinutes is omitted, interaction snapping follows this active value as zoom changes.
rowSizeControls row density in pixels.
nonWorkingTimeStyles closed or outside-business-hours cells in the scheduler body.
grid.eventScheduler = {
view: 'week',
weekStartDate: '2026-06-08',
timeRange: { start: '06:00', end: '22:00' },
slotMinutes: 30,
rowSize: 40,
timeLabelFormatter: (minutes) => {
const hour = Math.floor(minutes / 60);
const minute = minutes % 60;
return `${hour % 12 || 12}:${String(minute).padStart(2, '0')} ${hour < 12 ? 'AM' : 'PM'}`;
},
timeLabelTemplate: (h, context) =>
h('span', { class: 'planner-time-label' }, context.timeLabel),
timeRowProperties: (context) => ({
class: context.currentTimeLabel ? 'planner-time-row--current' : 'planner-time-row',
style: {
'--planner-time-start': context.startMinutes,
},
'data-planner-time': context.timeLabel,
}),
nonWorkingTime: {
enabled: true,
workingDays: [1, 2, 3, 4, 5],
workingHours: { start: '08:00', end: '18:00' },
className: 'planner-closed-hours',
},
};

customization.cells.timeTemplate and customization.cells.timeProperties layer over the direct timeLabelTemplate and timeRowProperties hooks when both are provided. Use rowSize for compact, dense, or comfortable density presets, and use timeRange when night hours should be hidden from the grid instead of only styled as closed.

HookSurface
timeTemplate / timePropertiesTime-label rows in week-style grids.
dayTemplate / dayPropertiesDay/time slots in week-style grids.
resourceTemplate / resourcePropertiesResource rows in resource timeline grids.
resourceGroupTemplate / resourceGroupPropertiesGroup rows when resource grouping is enabled.
timelineTemplate / timelinePropertiesTimeline cells in resource timeline grids.
grid.eventScheduler = {
view: 'resourceTimeline',
weekStartDate: '2026-06-08',
customization: {
cells: {
resourceProperties: ({ resource, unassigned, depth }) => ({
class: [
resource?.role ? `resource-row--${resource.role.toLowerCase()}` : '',
unassigned ? 'resource-row--open-demand' : '',
],
style: { '--resource-depth': depth },
'data-resource-role': resource?.role,
}),
timelineProperties: ({ date, slotIndex, segmentCount }) => ({
class: segmentCount > 0 ? 'timeline-slot--busy' : 'timeline-slot--open',
'data-slot-key': `${date}:${slotIndex}`,
}),
},
},
};

When a cell template is provided, the scheduler renders that template instead of the default cell content for that slot. Continuous event bars are rendered by the Scheduler’s bar layer and remain independent of slot-cell content, so prefer cell properties when the goal is only styling or annotation.