TimeRanges

This feature provides an easy way to highlight ranges of time in a calendar's day and week views. Each time range is represented using the TimeRangeModel.

Time ranges
//<code-header>
fiddle.title = 'Time ranges';
//</code-header>
const calendar = new Calendar({
    // Features named by the properties are included.
    features : {
        // Enable and optionally configure the timeRanges feature:
        timeRanges : {
            // configuration goes here
        }
    },

    // Start life in day view at this date
    date : '2020-03-03',
    mode : 'day',

    // Modes are the views available in the Calendar.
    // An object is used to configure the view.
    modes : {
        day : {
            dayStartTime : 8
        },
        week : {
            dayStartTime : 8
        },
        agenda : null,
        month  : null,
        year   : null
    },

    // Used to create view titles
    dateFormat         : 'DD MMM YYYY',
    hideNonWorkingDays : true,

    // The utility panel which is at the left by default.
    // Not enough width here, so don't include it.
    sidebar : false,

    // CrudManager arranges loading and syncing of data in JSON form from/to a web service
    crudManager : {
        autoLoad : true,
        loadUrl  : 'data/Calendar/examples/feature/time-ranges.json'
    },

    appendTo : targetElement,
    height   : 700
});

TimeRange types

Time ranges can take a few different forms:

  • A line at the startDate with optional tooltip based on the name.
  • A styled region between the startDate and endDate. The cls field is used to apply the desired style to the time range element.
  • A titled region based on the name field, between the startDate and endDate. The cls field can be used to apply the styling to the time range element. The color and iconCls fields can be used to apply a background color and icon to the header element. An optional footer can also be added.

Disabling the feature will hide all time ranges.

TimeRange DOM structure

A rendered time range element is divided into three sections: a header, body, and footer laid out horizontally across the day cell. This is achieved using flexbox column layout, but rotating the writing-mode to be vertical-rl or vertical-lr so that text is displayed vertically and the primary axis is horizontal.

The time range's cls field is applied to the encapsulating element in addition to the b-cal-time-range class. The arrangement is as follows:

  <inset>px                flexed                 <inset>px
┌────────────┬──────────────────────────────────┬────────────┐
│            │                                  │            │
│     H      │                                  │     F      │
│     e      │                                  │     o      │
│     a      │                                  │     o      │
│     d      │                                  │     t      │
│     e      │                                  │     e      │
│     r      │                                  │     r      │
│            │                                  │            │
└────────────┴──────────────────────────────────┴────────────┘

The visual order can be reversed by setting the alignment field to 'end'.

If the time range has a name, the header section will be rendered with that name and will be inset pixels wide. The header section may also include an icon if the time range has an iconCls field. The header section is rendered with the b-cal-time-range-header CSS class.

The body section occupies the space between the header and footer sections and is rendered with the b-cal-time-range-body CSS class.

If the time range has an footer, a footer section will also be rendered inset pixels wide containing that text. The footer section is rendered with the b-cal-time-range-footer CSS class.

The sections are rendered across the day cell with the name and footer text rotated. The whole element leaves the end gutter area free. To have time ranges render across the gutter area too, apply the CSS class b-cal-time-range-overlay-gutter to a cls time range's cls field.

The body section has no rendition by default, but can be styled using the cls field in addition to the b-cal-time-range-body class.

A header and footer will occupy space on the inline-start and inline-end sides of the time range. This can be reversed by specifying the alignment as 'end'.

The width of the header and footer is determined by the inset configuration of the view's layout.

The three sections of a time range can be customized using the following CSS classes:

  • .b-cal-time-range-header : The header element
  • .b-cal-time-range-body : The body element
  • .b-cal-time-range-footer : The footer element

A "part" renderer can return null to suppress visibility of a header or a footer.

Integration with ScheduleTooltip feature

The ScheduleTooltip feature's renderer will be passed hovered time ranges by default. The content may be customized as in the example below.

Resource-specific TimeRanges

To display time range elements for individual resources, you can include resourceTimeRanges in the loaded data. You can use this feature to visualize resource specific working times for example. The results are shown in views which display resources, such as DayResourceView or subviews of a ResourceView. As with regular time ranges, you can include a recurrenceRule to specify repeating patterns.

Resource time ranges
//<code-header>
fiddle.title = 'Resource time ranges';
CSSHelper.insertRule(`
.non-working-time {
    .b-cal-time-range-body {
        background-color : var(--b-day-view-outside-core-hours-color);
    }
}
`, targetElement.getRootNode());
CSSHelper.insertRule(`.b-cal-schedule-tooltip .b-icon.fa-warning {
    &::before {
        color : #ae2929;
    }
}
`, targetElement.getRootNode());
//</code-header>
new SlideToggle({
    insertFirst : targetElement,
    label       : 'Show time ranges',
    checked     : true,
    onChange({ value }) {
        calendar.features.timeRanges.enabled = value;
    }
});

const calendar = new Calendar({
    sidebar  : false,
    appendTo : targetElement,
    height   : 700,
    // Features named by the properties are included.
    features : {
        // Enable and optionally configure the timeRanges feature:
        timeRanges      : true,
        scheduleTooltip : {
            renderer(view, date, preciseDate, events, timeRanges) {
                // Are we over non working time ranges?
                const inNonWorkingTime = timeRanges.some(({ cls }) => cls['non-working-time']);

                // Return the default tooltip content plus our custom info if any
                return [
                    { tag : 'span', html : this.defaultRenderer(view, preciseDate, events, timeRanges) },
                    inNonWorkingTime && {
                        text  : 'Non-working time',
                        class : 'b-icon fa-warning'
                    }
                ];
            }
        },
        // One feature, "drag" handles move, resize and create drag gestures.
        drag : {
            // Each drag mode has a separate validation callback.
            // We route them all to one on the calendar instance
            validateCreateFn : 'up.validateDrag',
            validateMoveFn   : 'up.validateDrag',
            validateResizeFn : 'up.validateDrag'
        }
    },

    // Called when double-click, or context menu's "New event" is triggered
    onBeforeAutoCreate({ view, startDate, endDate, domEvent }) {
        return this.validateEventDates(view, startDate, endDate, view.getResourceRecord?.(domEvent));
    },

    // Check that we never schedule anything that intersects with a disabled timeRange
    validateDrag({ drag, eventRecord, event }) {
        return this.validateEventDates(drag.target.view, eventRecord.startDate, eventRecord.endDate, drag.target.view.getResourceRecord?.(event));
    },

    validateEventDates(view, startDate, endDate, resource) {
        // If creating in a DayView, enforce disabled time ranges.
        if (view.isDayView) {
            // If any of the disabled time ranges intersect with the event being created or moved,
            // then we cannot allow the drag.
            if (view.getTimeRanges(view.startDate, view.endDate, resource).some(timeRange => {
                if (timeRange.cls['non-working-time']) {
                    if (DateHelper.intersectSpans(startDate, endDate, timeRange.startDate, timeRange.endDate)) {
                        Toast.show(`That is in non working time ${DateHelper.format(timeRange.startDate, 'HH:mm')} to ${DateHelper.format(timeRange.endDate, 'HH:mm')}`);
                        return true;
                    }
                }
            })) {
                return false;
            }
        }

        return true;
    },

    date              : '2026-01-27',
    resourceImagePath : '../examples/_shared/images/transparent-users/',

    // CrudManager arranges loading and syncing of data in JSON form from/to a web service
    crudManager : {
        inlineData : {
            resources : [
                {
                    id         : 1,
                    name       : 'Don Taylor',
                    eventColor : 'blue',
                    image      : 'dan.png'
                },
                {
                    id         : 2,
                    name       : 'Jenny Brown',
                    eventColor : 'deep-orange',
                    image      : 'linda.png'
                },
                {
                    id         : 3,
                    name       : 'John Adams',
                    eventColor : 'orange',
                    image      : 'malik.png'
                }
            ],
            events : [
                {
                    id         : 1,
                    resourceId : 1,
                    name       : 'Make marketing plan',
                    startDate  : '2026-01-26 11:00',
                    endDate    : '2026-01-26 12:00',
                    eventType  : 'Meeting'
                },
                {
                    id         : 2,
                    resourceId : 2,
                    name       : 'Read spec.',
                    startDate  : '2026-01-26 12:00',
                    endDate    : '2026-01-26 15:00'
                },
                {
                    id         : 3,
                    resourceId : 1,
                    name       : 'Sign documents',
                    startDate  : '2026-01-27 13:00',
                    endDate    : '2026-01-27 16:00'
                },
                {
                    id         : 4,
                    resourceId : 3,
                    name       : 'Board meeting',
                    startDate  : '2026-01-28 09:00',
                    endDate    : '2026-01-28 11:00',
                    eventType  : 'Meeting'
                },
                {
                    id         : 5,
                    resourceId : 2,
                    name       : 'Sales call',
                    startDate  : '2026-01-29 10:00',
                    endDate    : '2026-01-29 12:00'
                },
                {
                    id         : 6,
                    resourceId : 3,
                    name       : 'Customer visit',
                    startDate  : '2026-01-26 11:00',
                    endDate    : '2026-01-26 13:00',
                    location   : 'Customer office'
                },
                {
                    id         : 7,
                    resourceId : 1,
                    name       : 'Prepare happy hour',
                    startDate  : '2026-01-30 14:00',
                    endDate    : '2026-01-30 17:00'
                }
            ],
            resourceTimeRanges : [
                {
                    id             : 1,
                    resourceId     : 1,
                    cls            : 'non-working-time b-cal-time-range-overlay-gutter',
                    startDate      : '2026-01-26 00:00',
                    endDate        : '2026-01-26 09:00',
                    recurrenceRule : 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR'
                },
                {
                    id             : 2,
                    resourceId     : 1,
                    cls            : 'non-working-time b-cal-time-range-overlay-gutter',
                    startDate      : '2026-01-26 17:00',
                    endDate        : '2026-01-27 00:00',
                    recurrenceRule : 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR'
                },
                {
                    id             : 3,
                    resourceId     : 2,
                    cls            : 'non-working-time b-cal-time-range-overlay-gutter',
                    startDate      : '2026-01-26 00:00',
                    endDate        : '2026-01-26 10:00',
                    recurrenceRule : 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR'
                },
                {
                    id             : 4,
                    resourceId     : 2,
                    cls            : 'non-working-time b-cal-time-range-overlay-gutter',
                    startDate      : '2026-01-26 18:00',
                    endDate        : '2026-01-27 00:00',
                    recurrenceRule : 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR'
                }
            ]
        }
    },
    tbar : null,

    modes : {
        day         : null,
        week        : null,
        month       : null,
        year        : null,
        agenda      : null,
        dayresource : {
            dayStartTime : 7,
            dayEndTime   : 20,
            hourHeight   : 50,

            // Save a little space by hiding weekends.
            hideNonWorkingDays : true,

            // Configure a nice min-width for the resource columns
            minResourceWidth : '12em'
        }
    }
});

Example data showing Resource 1 with shaded days until 9am, and Resource 2 shaded until 8am in the morning.

"resourceTimeRanges" : {
    "rows" : [
      {
        "id"             : 1,
        "resourceId"     : 1,
        "startDate"      : "2026-01-26 00:00",
        "endDate"        : "2026-01-26 09:00",
        "recurrenceRule" : "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR"
      },
      {
        "id"             : 2,
        "resourceId"     : 2,
        "startDate"      : "2026-01-26 00:00",
        "endDate"        : "2026-01-27 08:00",
        "recurrenceRule" : "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR"
      }
   ]
}

This feature is disabled by default.

Configs

23

Common

bodyRendererAbstractTimeRanges
disabledInstancePlugin
dragTipTemplateTimeRanges
enableResizingAbstractTimeRanges
headerRendererAbstractTimeRanges
hoverTooltipAbstractTimeRanges
listenersEvents
showHeaderElementsAbstractTimeRanges
showTooltipAbstractTimeRanges
tooltipTemplateAbstractTimeRanges

Other

headerWidth: Number= 40

The number of pixels or proportion of the overall width to allocate for time range headers.

Values less than 1 are the fractional proportion of the width (for example, 0.04 is 4% of the width), while values greater than or equal to 1 are a number of pixels.

An empty function by default, but provided so that you can override it.

This function is called each time a time range is rendered to allow developers to mutate the element metadata, or the CSS classes to be applied to the rendered element.

It's called with a TimeRangeRenderInfo object containing the time span record, and a renderData object which allows you to mutate event metadata such as cls and style.

A non-null return value from the renderer is used as the element body content. A nullish return value results in the default renderer for the element.

 timeRanges : {
     renderer ({ timeRange, renderData }) {
         if (timeRange.name === 'Doctors appointment') {
             renderData.style.fontWeight = 'bold';
             renderData.cls['custom-cls'] = 1;

             return 'Special doctors appointment';
         }
     }
 }
When returning content, be sure to consider how that content should be encoded to avoid XSS (Cross-Site Scripting) attacks. This is especially important when including user-controlled data such as the event's `name`. The function encodeHtml as well as xss can be helpful in these cases.

For example:

 timeRanges : {
     renderer ({ timeRange, renderData }) {
         return StringHelper.xss`Special ${timeRange.name}`;
     }
 }

For advanced rendering, this config can be a TimeRangeRenderer object with rendering functions for individual elements: header, body, footer, and outer. When a function is provided, that is equivalent to passing the header renderer. In other words, the above example is equivalent to the following:

 timeRanges : {
     renderer : {
         header({ timeRange, renderData }) {
             return StringHelper.xss`Special ${timeRange.name}`;
         }
     }
 }

Note that if the TimeRange has zero duration, it will be rendered as a line, and the header, body and footer renderers will not add any content. The outer renderer may mutate the domConfig property to affect how the line will be rendered.

ParameterTypeDescription
infoTimeRangeRenderInfo

An object that contains data about the time span being rendered.

Returns: String

Misc

clientInstancePlugin
instantUpdateTimeRanges
localeClassLocalizable
localizableLocalizable

Properties

22

Common

disabledInstancePlugin
showHeaderElementsAbstractTimeRanges

Class hierarchy

isTimeRanges: Boolean= truereadonly
Identifies an object as an instance of TimeRanges class, or subclass thereof.
isTimeRanges: Boolean= truereadonlystatic
Identifies an object as an instance of TimeRanges class, or subclass thereof.
isAbstractTimeRangesAbstractTimeRanges
isDelayableDelayable
isEventsEvents
isInstancePluginInstancePlugin
isLocalizableLocalizable

Lifecycle

configBase

Misc

clientInstancePlugin
localeHelperLocalizable
localeManagerLocalizable
storeTimeRanges

Other

hoverTooltipAbstractTimeRanges
timeRangesTimeRanges

Functions

31

Configuration

applyDefaultsstaticBase

Events

Lifecycle

destroystaticBase

Misc

doDisableInstancePlugin
initClassstaticBase
isOfTypeNamestaticBase
mixinstaticBase
optionalLstaticLocalizable

Other

createOnFrameDelayable
getTipHtmlAbstractTimeRanges
LstaticLocalizable
onEvents
relayAllEvents
shouldRenderRangeAbstractTimeRanges
triggerEvents
unEvents

Events

9
catchAllEvents
destroyEvents
disableInstancePlugin
enableInstancePlugin
timeRangeHeaderClickAbstractTimeRanges
timeRangeHeaderContextMenuAbstractTimeRanges
timeRangeHeaderDblClickAbstractTimeRanges

Event handlers

9
onDestroyEvents
onDisableInstancePlugin
onEnableInstancePlugin
onTimeRangeHeaderClickAbstractTimeRanges
onTimeRangeHeaderDblClickAbstractTimeRanges

Typedefs

5

A mutable object used to render an element of the time range.

ParameterTypeDescription
recordTimeRangeModel

The record being rendered

isLineBoolean

This is true if the TimeRange has zero duration, meaning it will be rendered as a line with no header, body or footer.

colorString

The color to be applied to the element

clsObject

An object whose truthy property names will be added to the element's CSS classList

styleObject

An object containing style properties for the element

outerTimeRangeRenderData

The render data for the outermost element. This property is present when rendering any of the inner elements. The outer element is rendered after all inner elements, meaning this object can be modified by an inner element renderer function.

headerTimeRangeRenderData

The render data for the header element. This property is present when rendering the outermost element. The corresponding element has already been rendered, meaning that this object should be considered read only.

bodyTimeRangeRenderData

The render data for the body element. This property is present when rendering the outermost element. The corresponding element has already been rendered, meaning that this object should be considered read only.

footerTimeRangeRenderData

The render data for the footer element. This property is present when rendering the outermost element. The corresponding element has already been rendered, meaning that this object should be considered read only.

An object containing rendering methods for the various elements of a time range. All functions are optional. The footer function is special in that there is no footer element by default. If a footer is desired, a footer renderer function must be provided.

ParameterTypeDescription
outerfunction

An optional function to be called to render the outermost element. This function is passed a TimeRangeRenderInfo object.

bodyfunction

An optional function to be called to render the body element. This function is passed a TimeRangeRenderInfo object.

headerfunction

An optional function to be called to render the header element. This function is passed a TimeRangeRenderInfo object.

footerfunction

An optional function to be called to render the footer element. This function is passed a TimeRangeRenderInfo object.

The object passed to a renderer function.

ParameterTypeDescription
renderDataTimeRangeRenderData

The render data object to modify

timeRangeTimeRangeModel

The record being rendered

domConfigDomConfig

The default DOM config. This is only passed to the outer renderer and represents the DOM config that will be used for the element. The className and style properties are applied after the renderer returns.

CSS variables

31
NameDescription
--b-calendar-time-range-border-widthTime range border width
--b-calendar-time-range-line-sizeTime range line size
--b-calendar-time-range-line-zoom-scaleTime range line zoom scale
--b-calendar-time-range-header-backgroundTime range header background
--b-calendar-time-range-border-colorTime range border color

Inherited