Skip to main content
Version: 5.35.0

Migrating from Bryntum to Mobiscroll

Overview

This article provides a comprehensive guide for migrating your scheduling solution from Bryntum to Mobiscroll. It highlights the key differences between the two libraries and outlines step-by-step instructions, covering installation, configuration, resources, events, and features, ensuring a smooth and informed transition.

Installation

Migrating from Bryntum to Mobiscroll starts with a different approach to installation, especially regarding package access and tooling.

Mobiscroll installation steps:

Install the Mobiscroll CLI (only needed once):

npm install -g @mobiscroll/cli

Configure Mobiscroll in your project (navigate to your project root folder and run):

mobiscroll config react

Alternatively, Mobiscroll also supports manual installation if you’re not using NPM. However, using NPM is generally the recommended approach for simplicity and maintainability.

Initialization

Bryntum:

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';

const App = () => {
return (
<BryntumSchedulerPro />
);
};

export default App;

Mobiscroll:

import { Eventcalendar } from '@mobiscroll/react';
import '@mobiscroll/react/dist/mobiscroll.min.css';

function App() {
return (
<Eventcalendar />
);
}

export default App;

View configuration

Key Differences:

  • With Mobiscroll, you get precise control over time ranges on Scheduler and Timeline views, plus feature-rich Event Calendar and Agenda views for seamless scheduling.
  • Bryntum provides built-in view presets.

Bryntum Scheduler Pro:

For the Bryntum Scheduler, the time axis is configured using three settings: startDate, endDate, and viewPreset. The startDate and endDate define the overall date range visible on the axis, while the viewPreset controls its visual layout and determines which specific dates are displayed.

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';

const schedulerproProps = {
startDate : new Date(2017, 0, 1, 6),
endDate : new Date(2017, 0, 1, 20),
viewPreset : 'hourAndDay'
};

const App = () => {
return (
<BryntumSchedulerPro
{...schedulerproProps}
/>
);
};

export default App;

Mobiscroll Timeline view:

In the Mobiscroll Timeline view, the timeline object within the view option allows you to customize the visible days and the timeline’s scale. You can specify which days to display (e.g., weekdays), set the time scale (e.g., 30-minute intervals), and define the frequency of the labels shown (e.g., every 15 minutes).

import { Eventcalendar } from '@mobiscroll/react';
import { useMemo } from 'react';
import '@mobiscroll/react/dist/css/mobiscroll.min.css';

function App() {

const myView = useMemo(
() => ({
timeline: {
type: 'day',
size: 1,
startTime: '06:00',
endTime: '20:00',
}
}),
[],
);

return (
<Eventcalendar view={myView} defaultSelectedDate="2017-01-01" /> // if you want to set the initial view to a specific date
);
}

export default App;

Check out how you can configure the Timeline view in this live example.

Bryntum Calendar view config:

In the Bryntum Calendar, the date option sets the initial date that the Calendar, its sidebar date picker, and the active view should center around upon initialization. The mode option determines which of the built-in views (such as day, week, or month) is active by default.

import { BryntumCalendar } from '@bryntum/calendar-react';
@import "@bryntum/calendar/calendar.stockholm.css";

const calendarProps = {
date : new Date(2020, 9, 12),
mode : 'week',
};

const App = () => {
return (
<BryntumCalendar
{...calendarProps}
/>
);
};

export default App;

Mobiscroll Scheduler:

You can customize the visible days and hours, as well as the time grid scale, using the schedule object under the view option. This allows you to define which days are shown (e.g., weekdays), set the visible time range (e.g., 8 AM to 6 PM), adjust the time scale (e.g., 30-minute intervals), and control the frequency of the labels (e.g., every 15 minutes).

import { Eventcalendar } from '@mobiscroll/react';
import '@mobiscroll/react/dist/css/mobiscroll.min.css';
import { useMemo } from 'react';

function App() {

const myView = useMemo(
() => ({
schedule: {
type: 'week',
}
}),
[],
);

return (
<Eventcalendar view={myView} defaultSelectedDate="2020-09-12" />
);
}

export default App;

Check out how you can configure the Scheduler view in this live example.

Resource configuration

Migrating resource data from Bryntum to Mobiscroll should be relatively straightforward.

Bryntum Scheduler Pro – resource definition:

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';
import { useMemo } from 'react';

const App = () => {
const myResources = useMemo(
() => [
{ id: 'r1', name: 'Mike' },
{ id: 'r2', name: 'Linda' },
// ...
],
[],
);

return (
<BryntumSchedulerPro
resources={myResources}
/>
);
};

export default App;

Mobiscroll Timeline view/ Scheduler – resource definition:

import { Eventcalendar } from '@mobiscroll/react';
import '@mobiscroll/react/dist/css/mobiscroll.min.css';
import { useMemo } from 'react';

function App() {
const myResources = useMemo(
() => [
{ id: 'r1', name: 'Mike' },
{ id: 'r2', name: 'Linda' },
// ...
],
[],
);

return (
<Eventcalendar
resources={myResources}
/>
);
}

export default App;

As shown above, both Bryntum and Mobiscroll use similar structures for defining resources, typically including id and name properties. Like Bryntum, Mobiscroll also supports a wide range of additional properties, as demonstrated in this example.

For more advanced use cases, refer to the Mobiscroll documentation for additional options, including custom rendering and templating of resources. You can also explore our demo page for detailed resource configuration examples.

Event migration

As shown above, there are clear differences in how events are structured between Bryntum and Mobiscroll. Bryntum defines an event inside the events option using a startDate, along with a duration and durationUnit to determine the end time. In contrast, Mobiscroll uses the data option and explicit start and end properties for defining the event period.

Event structure comparison

Bryntum:

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';
import { useMemo } from 'react';

const App = () => {

const myEvents = useMemo(
() => [
{
id: 1,
resourceId: 'r1',
startDate: new Date(2017, 0, 1, 10),
duration: 2,
durationUnit: 'h',
name: 'Click me'
}
],
[],
);

return (
<BryntumSchedulerPro
events={myEvents}
/>
);
};

export default App;

Mobiscroll:

import { Eventcalendar } from '@mobiscroll/react';
import '@mobiscroll/react/dist/css/mobiscroll.min.css';
import { useMemo } from 'react';

function App() {

const myEvents = useMemo(
() => [
{
id: 1,
resource: 'r1',
start: '2017-01-01T10:00',
end: '2017-01-01T12:00',
title: 'Click me'
}
],
[],
);

return (
<Eventcalendar
data={myEvents}
/>
);
}

export default App;

Converting Bryntum events to Mobiscroll format

Here’s a simple example of how to convert Bryntum-style events into the format used by Mobiscroll:

useEffect(() => {
if (bryntumEvents && bryntumEvents.length) {
const convertedEvents = bryntumEvents.map(event => {
const start = new Date(event.startDate);
const end = new Date(start.getTime() + event.duration * 60 * 60 * 1000);

return {
id: event.id,
title: event.name,
start,
end,
resource: event.resourceId
};
});

setMobiscrollEvents(convertedEvents);
}
}, [bryntumEvents]);

Every project may have its own unique data format and requirements, so this script serves only as a basic starting point. You’ll likely need to adapt your transformation logic to fit your application’s specific needs.

Loading and saving data

When selecting a scheduling or calendar UI component, one of the most important factors to evaluate is how the component loads and saves data. The chosen approach can significantly influence performance, scalability, and integration complexity.

We will examine how each framework handles:

  • Loading data from local or remote sources.
  • Saving or synchronizing changes to a backend system.

Loading data

Bryntum:

  • Bryntum components use stores, structured data collections that manage entities such as resources, events, and project details.
  • Data is typically loaded from remote REST endpoints (e.g., /load, /read-resources) that return JSON. These endpoints can support filtering and chunking to optimize handling of large datasets.
  • Lazy loading (or paginated loading) is supported, allowing data to be fetched on demand as the user scrolls or navigates, minimizing initial load times and memory usage.
  • The backend layer is fully decoupled, enabling the use of any technology stack (Node.js, PHP, Java, etc.) to deliver JSON payloads to the Bryntum frontend.

Mobiscroll:

Let’s see an example for each case:

Local data

Bryntum:

You can use the events option for passing the data inline.

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';

const myData = [
{
id: 1,
resourceId: 'r1',
startDate: new Date(2017, 0, 1, 10),
duration: 2,
durationUnit: 'h',
name: 'Click me'
}
];

function App() {
return <BryntumSchedulerPro events={myData} />
}

Mobiscroll:

Pass the event array to the data option.

import { Eventcalendar } from "@mobiscroll/react";
import '@mobiscroll/react/dist/css/mobiscroll.min.css';

const myData = [
{
id: 1,
resource: 'r1',
start: '2017-01-01T10:00',
end: '2017-01-01T12:00',
title: 'Click me'
}
];

function App() {
return <Eventcalendar data={myData} />
}

Remote data

Bryntum

You can use a project definition that solves the loading of the events from the backend.

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';

const schedulerproProps = {
// ... other configs
project : {
autoLoad : true
transport : {
load : {
url : 'data/data.json'
}
},
}
};

const App = () => {
return (
<BryntumSchedulerPro
{...schedulerproProps}
/>
);
};

export default App;

Mobiscroll

In case of Mobiscroll, you can also use the onPageLoading pevent to load the data (on demand) relevant to the currently active view. The event fires every time the date range of the view changes, for example, when someone navigates the event calendar. Getting the events in real time as the user interacts with the UI improves load performance and always serves the most recent data.

import { Eventcalendar, getJson } from '@mobiscroll/react'
import '@mobiscroll/react/dist/css/mobiscroll.min.css';
import { useCallback, useState } from 'react'

const myView = {
schedule: { type: 'day' }
};

function App() {
const [myEvents, setEvents] = useState([]);

const handlePageLoading = useCallback((args) => {
const year = args.month.getFullYear();
const month = args.month.getMonth();
const day = args.month.getDate();

getJson(
'https://example.remotedata.com/weeklyevents/?year=' + year + '&month=' + month + '&day=' + day,
(data) => {
setEvents(data);
},
'jsonp'
)
}, []);

return <Eventcalendar data={myEvents} onPageLoading={handlePageLoading} view={myView} />
}

In case of the timeline view, data can also be loaded dynamically during scrolling. Scrolling vertically or horizontally triggers the onVirtualLoading lifecycle event, which can be used to load data incrementally during scrolling.

Saving data

Bryntum

  • By enabling autoSync: true in the project configuration, local changes automatically trigger API requests to persist modifications without additional boilerplate.

Example:

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';

const schedulerproProps = {
// ... other configs
project : {
autoSync : true,
syncUrl : 'save.php',
}
};

const App = () => {
return (
<BryntumSchedulerPro
{...schedulerproProps}
/>
);
};

export default App;

Mobiscroll

  • Persistence is managed by listening to Mobiscroll’s CRUD lifecycle events.
  • The Event Calendar exposes a variety of events that are triggered on certain actions made on calendar events. These events can be used to send your data to your API or save it to persistent storage.

Example for saving, updating, and deleting an event through an API:

import { Eventcalendar } from "@mobiscroll/react";
import '@mobiscroll/react/dist/css/mobiscroll.min.css';
import { useCallback, useState } from "react";

const myView = {
schedule: { type: "week" },
};

function App() {
const [myEvents] = useState([]);

const saveEvent = useCallback((args) => {
fetch('add.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(args.event)
});
}, []);

const updateEvent = useCallback((args) => {
fetch('update.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(args.event)
});
}, []);

const deleteEvent = useCallback((args) => {
fetch('delete.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(args.event)
});
}, []);

return <Eventcalendar
view={myView}
onEventCreated={saveEvent}
onEventUpdated={updateEvent}
onEventDeleted={deleteEvent}
data={myEvents}
/>
}

Mobiscroll offers a flexible, event-driven approach suitable for both lightweight client-side setups and API-driven applications. Developers are responsible for implementing their own persistence logic, allowing for high adaptability but requiring more manual integration effort.

Both libraries are capable of handling modern scheduling needs, but the choice depends largely on application scale, data complexity, and desired control over the persistence layer.

Lifecycle events

Both libraries, Bryntum and Mobiscroll, provide a comprehensive set of lifecycle event hooks, enabling deep customization and integration with your application logic. These events are emitted at various stages of a component’s lifecycle, offering developers full control to inject custom behavior and extend default functionality.

Whether you’re looking to manipulate data before rendering, respond to user interactions, or perform cleanup tasks, Mobiscroll’s event system offers the flexibility to tailor components to your specific needs.

When migrating between Bryntum and Mobiscroll, it’s important to note that most lifecycle events follow similar patterns across both libraries. This alignment minimizes friction during the transition process and helps preserve custom behaviors with minimal adjustments.

One such example is how each library handles a double-click on a cell. Below is a comparison of the respective event handlers and their parameters.

Bryntum

In Bryntum, the onCellDblClick event is triggered when a user double-clicks a grid cell. This event provides access to several key objects that describe the interaction and context:

  • event: Object - The Bryntum event object
  • grid: Grid - The grid instance
  • record: Model - The record representing the row
  • column: Column - The column to which the cell belongs
  • cellElement: HTMLElement - The cell HTML element
  • target: HTMLElement - The target element
  • event: MouseEvent - The native DOM event

Example:

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';
import { useRef } from 'react';

const App = () => {
const schedulerRef = useRef(null);

const handleCellDblClick = (event) => {
console.log('Cell double-clicked:', event.date, event.resourceRecord);

// Example: open the event editor dialog
// const scheduler = schedulerRef.current.instance;
// scheduler.editEventDialog.show({
// startDate: event.date,
// resourceRecord: event.resourceRecord
// });
};

return (
<BryntumSchedulerPro
ref={schedulerRef}
onCellDblClick={handleCellDblClick}
/>
);
};

export default App;

Mobiscroll

Mobiscroll components (e.g., Event Calendar, Scheduler, Timeline) expose a similar onCellDoubleClick event, which is fired when a cell is double-clicked. It includes contextual information that allows for granular control over the interaction:

  • args - The event argument with the following properties:
    • date: Date - The date of the clicked cell.
    • domEvent: Event - The DOM event of the click.
    • events: Array - The events for the clicked date.
    • resource: string | number - The id of the resource where the cell was clicked, if resources are set.
    • selected: boolean - Specifies if the day is currently selected or not (before it was clicked).
    • source: 'calendar' | 'schedule' | 'timeline' - The view where the cell was clicked.
    • target: HTMLElement - The DOM element of the clicked cell.
  • inst - The component instance.

Example:

import { Eventcalendar } from '@mobiscroll/react';
import '@mobiscroll/react/dist/css/mobiscroll.min.css';
import { useCallback } from 'react';

const App = () => {

const handleCellDblClick = useCallback((args) => {
console.log('Cell double-clicked:', args.date, args.resource);

// Example: open a custom dialog to create a new event
// showCreateEventDialog(args.date, args.resource);
}, []);

return (
<Eventcalendar
onCellDoubleClick={handleCellDblClick}
/>
);
};

export default App;

Although the naming conventions and parameter structures differ slightly between Bryntum and Mobiscroll, the overall event purpose and customization potential remain aligned. Developers familiar with Bryntum’s event model will find it straightforward to adapt similar functionality in Mobiscroll, ensuring a smooth migration path with minimal overhead.

To explore the full list of available Mobiscroll lifecycle events and understand how they can be leveraged, please refer to the documentation.

Additionally, you can see these events in action through live, interactive examples for the following Mobiscroll components:

These examples provide hands-on insights into how lifecycle events work in practice.

Feature migration

As a final step, let’s explore how core features from Bryntum can be replicated using Mobiscroll. While some capabilities are available out of the box in Bryntum, Mobiscroll often requires more explicit setup but offers much more flexibility.

Drag & Drop functionality

  • Bryntum enables drag-and-drop operations by default with no extra configuration needed.
  • In Mobiscroll, the D&D features must be enabled explicitly via configuration options.

Enabling Drag & Drop in Mobiscroll:

import '@mobiscroll/react/dist/css/mobiscroll.min.css';
import { Eventcalendar } from '@mobiscroll/react';

function App() {

return (
<Eventcalendar
clickToCreate={true}
dragToCreat={true}
dragToMove={true}
dragToResize={true}
eventDelete={true}
/>
);
}

export default App;

This configuration allows users to create, move, resize, and delete events in Mobiscroll.

Switching Views (Calendar/Scheduler/Agenda)

  • Bryntum enables switching views by default with no extra configuration needed.
  • Mobiscroll doesn’t include a built-in view-switching UI by default. However, it offers greater flexibility by allowing you to implement a custom header where you can design the view-switching experience to fit your needs. For example, you can use a dropdown menu or segmented controls to let users switch between views like Calendar, Scheduler, Agenda, or any other layout that fits your use case.

Bryntum:

import { BryntumCalendar } from '@bryntum/calendar-react';
@import "@bryntum/calendar/calendar.stockholm.css";

const calendarProps = {
date : new Date(2020, 9, 12),
mode : 'week',
};

const App = () => {
return (
<BryntumCalendar
{...calendarProps}
/>
);
};

export default App;

Mobiscroll:

In Mobiscroll, switching between views like Day, Week, or Month requires setting up a custom header along with event listeners to handle the view changes. You can see an example of this implementation here.

import '@mobiscroll/react/dist/css/mobiscroll.min.css';
import {
CalendarNav,
CalendarNext,
CalendarPrev,
CalendarToday,
Eventcalendar,
getJson,
Segmented,
SegmentedGroup,
} from '@mobiscroll/react';
import { useCallback, useEffect, useState } from 'react';

function App() {
const [view, setView] = useState('month');
const [myEvents, setEvents] = useState([]);

const [calView, setCalView] = useState({
calendar: { labels: true },
});

const changeView = useCallback((event) => {
let calView;

switch (event.target.value) {
case 'year':
calView = {
calendar: { type: 'year' },
};
break;
case 'month':
calView = {
calendar: { labels: true },
};
break;
case 'week':
calView = {
schedule: { type: 'week' },
};
break;
case 'day':
calView = {
schedule: { type: 'day' },
};
break;
case 'agenda':
calView = {
calendar: { type: 'week' },
agenda: { type: 'week' },
};
break;
}

setView(event.target.value);
setCalView(calView);
}, []);

const customWithNavButtons = useCallback(
() => (
<>
<CalendarNav className="cal-header-nav" />
<div className="cal-header-picker">
<SegmentedGroup value={view} onChange={changeView}>
<Segmented value="year">Year</Segmented>
<Segmented value="month">Month</Segmented>
<Segmented value="week">Week</Segmented>
<Segmented value="day">Day</Segmented>
<Segmented value="agenda">Agenda</Segmented>
</SegmentedGroup>
</div>
<CalendarPrev className="cal-header-prev" />
<CalendarToday className="cal-header-today" />
<CalendarNext className="cal-header-next" />
</>
),
[changeView, view],
);

useEffect(() => {
getJson(
'https://trial.mobiscroll.com/events/?vers=5',
(events) => {
setEvents(events);
},
'jsonp',
);
}, []);

return (
<Eventcalendar
clickToCreate={true}
dragToCreate={true}
dragToMove={true}
dragToResize={true}
eventDelete={true}
renderHeader={customWithNavButtons}
height={750}
view={calView}
data={myEvents}
cssClass="md-switching-view-cont"
/>
);
}

export default App;

Timezones

Handling time zones accurately is crucial in calendar and scheduling applications, especially when working across regions or coordinating international events. Both Bryntum and Mobiscroll offer support for working with time zones, though they approach it differently in terms of configuration and underlying technology. So, let’s see a simple example of how this scenario is handled in the case of Bryntum and Mobiscroll.

Bryntum

Bryntum provides built-in time zone support across all of its scheduling products. This allows you to configure components to operate in a specific time zone, independent of the browser or system time.

To enable time zone conversion in Bryntum, simply set the timeZone configuration on the project object. You can use either:

  • an IANA time zone identifier (e.g., 'Europe/Stockholm'), or
  • a UTC offset in minutes (e.g., -120)

This configuration automatically adjusts the timeline headers, event/task start and end times, and all other time-based calculations to match the configured zone.

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';

const App = () => {

return (
<BryntumSchedulerPro
timeZone="Europe/Stockholm"
/>
);
};

export default App;

Mobiscroll

By default, Mobiscroll will not do any timezone conversion, will display the dates without modification, handling them as timezone-less. If your use case requires interpreting or displaying data in a different time zone, you can achieve this by using one of the supported third-party libraries for time zone conversion:

Mobiscroll exposes two configuration options to handle time zones:

  • dataTimezone option – the time zone in which your event data is stored (e.g., 'utc')
  • displayTimezone option – the time zone in which you want the data to be presented (e.g., 'Europe/Stockholm')

So, let’s say you want to use the Day.js timezone library. After installing it into your project, you can pass the dayjsTimezone object to the Timeline’s timezonePlugin option:

import { Eventcalendar, dayjsTimezone } from '@mobiscroll/react';
import dayjs from 'dayjs';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';

dayjs.extend(utc);
dayjs.extend(timezone);
dayjsTimezone.dayjs = dayjs;

function App() {
return <Eventcalendar
timezonePlugin={dayjsTimezone}
dataTimezone="utc"
displayTimezone="Europe/Stockholm"
/>
}

Also, feel free to explore live examples to see how time zones work in action:

Or you can also check advanced demos such as:

You can also store the timezone inside the event data, using the timezone property.

As a conclusion, both libraries, Bryntum and Mobiscroll, provide timezone support. Mobiscroll supports multiple timezone libraries (Moment-Timezone, Luxon, and Day.js), while Bryntum relies on react Date, which may introduce DST inconsistencies.

Conclusion

While Bryntum offers more built-in functionality out of the box, Mobiscroll provides greater flexibility, enabling tailored behavior through configuration and custom UI components:

In addition to drag & drop and custom view-switching, Mobiscroll also supports timezone handling and zooming levels. All of our views work seamlessly across both mobile and desktop environments, with full support for touch interactions.

As mentioned above, with some additional setup, most —if not all— features can be effectively replicated when migrating from Bryntum to Mobiscroll. If you have any specific questions or run into any issues, don’t hesitate to reach out — we’re happy to help.

Templating and renderers

Event templating

Bryntum

Bryntum handles templating for events, resources, and other UI elements through a flexible system that allows developers to customize content rendering using template functions or strings.

In case of Bryntum you can show any HTML structure inside an event bar using the eventRenderer.

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';
import { useMemo } from 'react';

const App = () => {

const myEvents = useMemo(() => [
{
id: 10,
resourceId: 'r1',
name: 'Custom Meeting',
startDate: '2017-01-01 09:00',
endDate: '2017-01-01 11:00',
duration: 2
}
], []);

const customEventRenderer = ({ eventRecord }) => {
return (
<div style={{ background: '#a8d8ea', borderRadius: '4px', padding: '4px' }}>
<strong>${eventRecord.name}</strong>
<div style={{ fontSize: '12px', color: '#444' }}>Duration: ${eventRecord.duration}h</div>
</div>
);
};

return (
<BryntumSchedulerPro
startDate="2017-01-01"
endDate="2017-01-02"
viewPreset="hourAndDay"
events={myEvents}
eventRenderer={customEventRenderer}
/>
);
};

export default App;

Mobiscroll

You can customize many parts of the Event Calendar by writing custom templates. In the context of plain react these templates are functions that return a string containing the html markup. You will find a comprehensive list of all the available render functions for the Event Calendar in the API templates section.

When you want to customize how the events look, depending on what your goal is, you have two options:

  • Customize the event content - Mobiscroll takes care of rendering the events in the correct order and also prints basic fields, like start/end, whether it is an allDay event or not and also takes care of coloring the event appropriately. Everything else comes from the custom template.
  • Customize the full event - Mobiscroll takes care of rendering the events in the correct order, but everything else comes form the template you write.

To define a custom template, pass a functional to the appropriate option that returns the desired html:

import { Eventcalendar } from '@mobiscroll/react';
import '@mobiscroll/react/dist/css/mobiscroll.min.css';
import { useCallback, useMemo } from 'react';

const App = () => {
const myView = useMemo(
() => ({
timeline: {
type: 'week',
}
}),
[],
);

const myEvents = useMemo(() => [
{
id: 10,
resourceId: 'r1',
name: 'Custom Meeting',
start: '2017-01-01T09:00',
end: '2017-01-01T11:00',
duration: 2
}
], []);

const customEventRenderer = useCallback((event) => {
const { name, duration } = event;
return (
<div style={{ background: '#a8d8ea', borderRadius: '4px', padding: '4px' }}>
<strong>{name}</strong>
<div style={{ fontSize: '12px', color: '#444' }}>Duration: {duration}h</div>
</div>
);
}, []);

return (
<Eventcalendar
view={myView}
data={myEvents}
renderScheduleEvent={customEventRenderer}
/>
);
};

export default App;

Feel free to explore live examples to see how event content templating work in action:

Feel free to explore live examples to see how full event templating work in action:

Resource templating

Bryntum

You can customize cell content and styling in a column using a renderer function.

To customize the column header, use the headerRenderer option.

import { BryntumSchedulerPro } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';
import { useMemo } from 'react';

const schedulerProProps = {
columns: [
{
text: 'Name',
field: 'name',
width: 130,
headerRenderer: () => <strong>Name</strong>,
renderer: ({ record }) => <strong>{record.name}</strong>,
},
{
text: 'City',
field: 'city',
width: 90,
headerRenderer: () => <i>City</i>,
renderer: ({ record }) => <i>{record.city}</i>,
},
],
startDate: new Date(2017, 0, 1, 6),
endDate: new Date(2017, 0, 1, 20),
viewPreset: 'hourAndDay',
};

const App = () => {
const myResources = useMemo(() => [
{ id: 1, name: 'Adam', city: 'Washington' },
{ id: 2, name: 'Eva', city: 'New York' }
], []);

return (
<div style={{ height: '100vh' }}>
<BryntumSchedulerPro
{...schedulerProProps}
resources={myResources}
/>
</div>
);
};

export default App;

Mobiscroll

In the case of Mobiscroll, we take a different approach. We provide various templating options (listed below), which allow you to customize the resources. This is unlike Bryntum, where customization requires modifying the columns with different renderers.

Scheduler

Use the renderResource option to customize the resource template of the Scheduler. Customize how the resource headers look and what they show. Utilize properties passed in the resources array. It takes a function that should return the desired markup.

Check out how you can style the resources in this example.

Timeline

In case of the Timeline view there are three places where you can customize the resource column:

  • Use the renderResource option to customize the resource template of the Timeline. Customize how the resource headers look and what they show. Utilize properties passed in the resources array.
  • Customize the empty cell content above the resource column with the renderResourceHeader option.
  • Or if you want to customize the empty cell content below the resource column you can achieve this with the renderResourceFooter option. This element only renders for the Timeline view, if the renderDayFooter option is present.

Check out how you can style these resource parts in this example.

import { Eventcalendar } from '@mobiscroll/react';
import '@mobiscroll/react/dist/css/mobiscroll.min.css';
import { useCallback, useMemo } from 'react';

const App = () => {
const myView = useMemo(
() => ({
timeline: {
type: 'week',
}
}),
[],
);

const myResources = useMemo(() => [
{ id: 1, name: 'Adam', city: 'Washington' },
{ id: 2, name: 'Eva', city: 'New York' }
], []);

const renderResourceHeader = useCallback(() => (
<>
<div className="my-resource-header">
<strong>Name</strong>
</div>
<div className="my-resource-header">
<i>City</i>
</div>
</>
), []);

const renderResource= useCallback((resource) => (
<>
<div className="my-resource-cell">
<strong>{resource.name}</strong>
</div>
<div className="my-resource-cell">
<i>{resource.city}</i>
</div>
</>
), []);

return (
<Eventcalendar
view={myView}
resources={myResources}
renderResource={renderResource}
renderResourceHeader={renderResourceHeader}
/>
);
};

export default App;

Header templating

The header of the Mobiscroll calendar can be fully customized to one's needs with the use of the renderHeader option.

Here's the list of the built in components of the default header. You can initialize these by putting the attributes on the elements:

  • mbsc-calendar-prev - Previous button component, that navigates to the previous month.
  • mbsc-calendar-next - Next button component, that navigates to the next month.
  • mbsc-calendar-today - Today button component, that navigates to the current date.
  • mbsc-calendar-nav - The title navigation button component, that opens the year/month navigation.

The following example will render the prev and next buttons and a custom title.

const myTitle = 'Awesome title';

const myHeader = () => {
return <>
<CalendarPrev />
<CalendarNext />
<div class="my-custom-title">{myTitle}</div>
</>
}

<Eventcalendar renderHeader={myHeader} />

Also, feel free to explore live examples to see how header templating work in action:

Other templating/ renderer options

Event Calendar

  • Date header templating - There are two approaches you can take:
    • Customize the date headers of the Event Calendar with the renderDay option by adding relevant content, labels or completely change how they look.
    • If you are looking to customize only the content and don't want to bother with the styling of the event, you can use the renderDayContent option.

Scheduler

  • Date header templating - There are two approaches you can take:

    • Customize the date headers of the Scheduler with the renderDay option by adding relevant content, labels or completely change how they look.
    • If you are looking to customize only the content and don't want to bother with the styling of the event, you can use the renderDayContent option.

    Check out how you can style the date header in this example.

Timeline

  • Templating the sidebar header and footer - Besides the resource template, an additional sidebar can be rendered on the opposite end of the row and there are three approaches you can take:

    • Use the renderSidebar option to render a custom sidebar on the right side of the Timeline.
    • Customize the empty cell content above the sidebar column with the renderSidebarHeader option.
    • Or if you want to customize the empty cell content below the sidebar column you can achieve this with the renderSidebarFooter option.

    Check out how you can style the sidebar parts in this example.

  • Date header and footer templating - The headers hold key information like the date, day of the week and in some cases it also holds the full date. Whenever you need to show extra information, or if you would like to change the styling or date format, time format you can use the various header templates, depending on the view configuration. You can also show a footer element, for displaying more information.

    Check out how you can style the date header and footer in this example.

  • Slots - Use the renderSlot option to customize the slot template of the Timeline view.

    Check out how you can style the slots in this example.

  • Variable event height - When using event templating, you might end up with various event heights, depending on the displayed content, e.g. larger description, list of tasks, etc. You can enable support for variable event heights by setting the eventHeight: 'variable' property for the timeline inside the view option.

    Check out how you can set and style the variable event height in this example.

Agenda

Localization

Bryntum

Bryntum supports localization by allowing developers to select from built-in locales or define custom ones. Key aspects include:

  • Locale files translate UI text, date formats, and number formats to the target language.
  • Custom locales can be created or modified using their locale structure.
  • Right-to-left (RTL) layout support is included
import { BryntumSchedulerPro, LocaleManager } from '@bryntum/schedulerpro-react';
import '@bryntum/schedulerpro/schedulerpro.stockholm.css';
import '@bryntum/schedulerpro/locales/schedulerpro.locale.FrFr';

LocaleManager.applyLocale('FrFr');

Mobiscroll

Mobiscroll enables localization by letting developers set language, date, and time formats both globally (across the entire application) and locally (on individual components). Highlights:

  • Global settings object lets developers set locale, theme, and format across the app (first example).
  • Each component (e.g., Date Picker, Event Calendar) supports locale switching and custom translations with simple configuration (second example).
  • RTL and calendar system support (Gregorian, Jalali, Hijri)
  • Quick override ability for localized formats ensures that adaptations can be made case-by-case or via global settings.

Example setting the locale option globally:

import { setOptions, localeFr } from '@mobiscroll/react';

setOptions({
// ...other config...
locale: localeFr // French locale applied globally
});

Example setting the locale at the component level:

import { Eventcalendar, localeFr } from '@mobiscroll/react';

export function MyComponent() {
return <Eventcalendar locale={localeFr} />;
}

Conclusion

Migrating from Bryntum Scheduler to Mobiscroll Scheduler involves rethinking certain configurations, especially around views, events, and feature toggles. While Bryntum comes with richer built-in functionality out of the box (like zooming, vertical timelines, and infinite scrolling), Mobiscroll shines in flexibility, responsive design, and easier timeline and calendar customizations.

The overall migration process includes:

  • Adjusting initialization patterns
  • Adapting view configurations
  • Mapping resources and events to Mobiscroll’s structure
  • Enabling features like drag-and-drop manually

With a clear understanding of both libraries’ capabilities and structures, you can migrate efficiently and take full advantage of Mobiscroll’s modern UI and feature-rich environment.

Considering migrating from Bryntum to Mobiscroll?

Schedule a call and let's chat about how we can help. We're here to support you in the migration process.