Styling
The Bryntum Scheduler is rendered in the DOM using regular HTML and CSS, and can be completely styled using CSS. It ships with both pre-compiled CSS bundles, and the original CSS files. The CSS includes different themes and colors, which can be used to alter how the Scheduler and its contents look.
You can also programmatically modify the appearance of cells, headers and events using renderers (depending on product).
Styling event bars using predefined styles and colors
Bryntum Scheduler ships with 10 predefined event styles, each available in 20+ predefined colors. Style and color can be specified for the entire scheduler, per resource or per event. Event settings overrides resource, which in its turn overrides the scheduler setting. The following snippet shows how to assign colors:
// Make all events blue by default
scheduler.eventColor = 'blue';
// Make all events assigned to a specific resource orange:
resource.eventColor = 'orange';
// Make a single event violet:
event.eventColor = 'violet';
This demo has one event per available color:
//<code-header>
fiddle.title = 'Event colors';
//</code-header>
const scheduler = new Scheduler({
appendTo : targetElement,
autoHeight : true,
rowHeight : 50,
autoAdjustTimeAxis : false,
columns : [
{
text : 'Name',
field : 'name',
width : 160
}
],
resources : [
{ id : 1, name : 'eventColor' }
],
events : [
{ resourceId : 1, startDate : '2025-05-04', duration : 3, durationUnit : 'day', name : 'red', eventColor : 'red' },
{ resourceId : 1, startDate : '2025-05-05', duration : 3, durationUnit : 'day', name : 'pink', eventColor : 'pink' },
{ resourceId : 1, startDate : '2025-05-06', duration : 3, durationUnit : 'day', name : 'magenta', eventColor : 'magenta' },
{ resourceId : 1, startDate : '2025-05-07', duration : 3, durationUnit : 'day', name : 'purple', eventColor : 'purple' },
{ resourceId : 1, startDate : '2025-05-08', duration : 3, durationUnit : 'day', name : 'deep-purple', eventColor : 'deep-purple' },
{ resourceId : 1, startDate : '2025-05-09', duration : 3, durationUnit : 'day', name : 'violet', eventColor : 'violet' },
{ resourceId : 1, startDate : '2025-05-10', duration : 3, durationUnit : 'day', name : 'indigo', eventColor : 'indigo' },
{ resourceId : 1, startDate : '2025-05-11', duration : 3, durationUnit : 'day', name : 'blue', eventColor : 'blue' },
{ resourceId : 1, startDate : '2025-05-12', duration : 3, durationUnit : 'day', name : 'light-blue', eventColor : 'light-blue' },
{ resourceId : 1, startDate : '2025-05-13', duration : 3, durationUnit : 'day', name : 'cyan', eventColor : 'cyan' },
{ resourceId : 1, startDate : '2025-05-14', duration : 3, durationUnit : 'day', name : 'teal', eventColor : 'teal' },
{ resourceId : 1, startDate : '2025-05-15', duration : 3, durationUnit : 'day', name : 'green', eventColor : 'green' },
{ resourceId : 1, startDate : '2025-05-16', duration : 3, durationUnit : 'day', name : 'light-green', eventColor : 'light-green' },
{ resourceId : 1, startDate : '2025-05-17', duration : 3, durationUnit : 'day', name : 'lime', eventColor : 'lime' },
{ resourceId : 1, startDate : '2025-05-18', duration : 3, durationUnit : 'day', name : 'yellow', eventColor : 'yellow' },
{ resourceId : 1, startDate : '2025-05-19', duration : 3, durationUnit : 'day', name : 'amber', eventColor : 'amber' },
{ resourceId : 1, startDate : '2025-05-20', duration : 3, durationUnit : 'day', name : 'orange', eventColor : 'orange' },
{ resourceId : 1, startDate : '2025-05-21', duration : 3, durationUnit : 'day', name : 'deep-orange', eventColor : 'deep-orange' },
{ resourceId : 1, startDate : '2025-05-22', duration : 3, durationUnit : 'day', name : 'brown', eventColor : 'brown' },
{ resourceId : 1, startDate : '2025-05-23', duration : 3, durationUnit : 'day', name : 'gray', eventColor : 'gray' },
{ resourceId : 1, startDate : '2025-05-24', duration : 3, durationUnit : 'day', name : 'light-gray', eventColor : 'light-gray' }
],
startDate : new Date(2025, 4, 3),
endDate : new Date(2025, 4, 24)
});Event styles are assigned in a very similar way:
// Make all events use "outlined" style by default
scheduler.eventStyle = 'outlined';
// Make all events assigned to a resource use "line" style:
resource.eventStyle = 'line';
// Make a single event "intended":
event.eventStyle = 'intendet';
And this demo shows the predefined styles:
//<code-header>
fiddle.title = 'Event styles';
//</code-header>
const scheduler = new Scheduler({
appendTo : targetElement,
autoHeight : true,
rowHeight : 50,
autoAdjustTimeAxis : false,
columns : [
{
text : 'Name',
field : 'name',
width : 160
}
],
resources : [
{ id : 1, name : 'eventStyle' }
],
events : [
{ resourceId : 1, startDate : '2025-01-05', duration : 2, durationUnit : 'day', name : 'tonal', eventStyle : 'tonal' },
{ resourceId : 1, startDate : '2025-01-05', duration : 2, durationUnit : 'day', name : 'outlined', eventStyle : 'outlined' },
{ resourceId : 1, startDate : '2025-01-08', duration : 2, durationUnit : 'day', name : 'traced', eventStyle : 'traced' },
{ resourceId : 1, startDate : '2025-01-08', duration : 2, durationUnit : 'day', name : 'filled', eventStyle : 'filled' },
{ resourceId : 1, startDate : '2025-01-11', duration : 2, durationUnit : 'day', name : 'bordered', eventStyle : 'bordered' },
{ resourceId : 1, startDate : '2025-01-11', duration : 2, durationUnit : 'day', name : 'indented', eventStyle : 'indented' },
{ resourceId : 1, startDate : '2025-01-14', duration : 2, durationUnit : 'day', name : 'rounded', eventStyle : 'rounded' },
{ resourceId : 1, startDate : '2025-01-14', duration : 2, durationUnit : 'day', name : 'line', eventStyle : 'line' },
{ resourceId : 1, startDate : '2025-01-17', duration : 2, durationUnit : 'day', name : 'dashed', eventStyle : 'dashed' },
{ resourceId : 1, startDate : '2025-01-17', duration : 2, durationUnit : 'day', name : 'minimal', eventStyle : 'minimal' }
],
startDate : new Date(2025, 0, 5),
endDate : new Date(2025, 0, 19)
});Give the Event styles demo a shot if you want to try different colors and styles.
If you want to control the appearance of events using custom CSS we recommend setting both eventColor and
eventStyle to null. This applies very basic styling that is easier to override using CSS.
Styling individual events using data fields
You can style individual events easily by populating a few predefined fields of the EventModel:
- cls Add a CSS class to the event bar element
- style Inline styles for the event bar element
- iconCls Define the icon for the event
These fields allow you to style each individually through event data.
//<code-header>
fiddle.title = 'Styling data';
CSSHelper.insertRule('.myStyle { color: #472e00; border-radius: 20px; }', targetElement.getRootNode());
//</code-header>
const scheduler = new Scheduler({
appendTo : targetElement,
autoHeight : true,
rowHeight : 50,
features : {
scheduleTooltip : false,
eventTooltip : {
template : ({ eventRecord }) => `Event data<pre>${JSON.stringify(eventRecord.data, undefined, 4)}</pre>`
}
},
resources : [
{ id : 1, name : 'Classy Mike' },
{ id : 2, name : 'Lisa Styles' },
{ id : 3, name : 'Iconic Dan' }
],
events : [
{ resourceId : 1, startDate : '2021-01-04', duration : 4, name : 'Styled with cls', cls : 'myStyle' },
{ resourceId : 2, startDate : '2021-01-06', duration : 4, name : 'Inline styles', style : 'background:#1e88e5; color: #90caf9' },
{ resourceId : 3, startDate : '2021-01-08', duration : 4, name : 'Custom icon', iconCls : 'fa fa-car-side' }
],
startDate : new Date(2021, 0, 3),
endDate : new Date(2021, 0, 13)
});You can also apply styling at runtime using the eventRenderer which is described below.
Sorting overlapping events
The vertical order (the non-timeaxis direction) of overlapping events rendered in a horizontal scheduler can be customized by overriding overlappingEventSorter function on the scheduler.
Note that the algorithms (stack, pack) that lay the events out expects them to be served in chronological order, be sure
to first sort by startDate to get predictable results.
For example:
let scheduler = new Scheduler({
overlappingEventSorter(a, b) {
return b.startDate.getTime() - a.startDate.getTime();
},
/*...*/
});
This live demo sorts events with identical timings by color:
//<code-header>
fiddle.title = 'Events order';
//</code-header>
const scheduler = new Scheduler({
appendTo : targetElement,
// makes scheduler as high as it needs to be to fit rows
autoHeight : true,
startDate : new Date(2018, 4, 6),
endDate : new Date(2018, 4, 13),
viewPreset : 'dayAndWeek',
columns : [
{ field : 'name', text : 'Name', width : 100 }
],
resources : [
{ id : 1, name : 'Mark' }
],
events : [
{ id : 1, resourceId : 1, name : '1. Call with a client', startDate : '2018-05-07', endDate : '2018-05-09', eventColor : 'green' },
{ id : 2, resourceId : 1, name : '2. Important meeting', startDate : '2018-05-07', endDate : '2018-05-09', eventColor : 'red' },
{ id : 3, resourceId : 1, name : '3. Audition', startDate : '2018-05-07', endDate : '2018-05-09', eventColor : 'green' }
],
overlappingEventSorter(a, b) {
const
comparedNames = a.name < b.name ? -1 : a.name === b.name ? 0 : 1,
comparedColors = (a.eventColor === 'red' && b.eventColor !== 'red') ? -1 : (a.eventColor !== 'red' && b.eventColor === 'red') ? 1 : comparedNames;
return a.startDateMS - b.startDateMS || a.endDateMS - b.endDateMS || comparedColors;
}
});Using a theme
Bryntum products have their "structural" CSS and themes separated. The structural CSS contains the basic layout and styling shared between all themes for the product. It defines a lot of CSS variables (CSS custom properties), that the themes then set to specific values to create the visual appearance.
The theme CSS files set CSS variables for all Bryntum products, so you can use the same theme file for all Bryntum products.
The Scheduler ships with four themes, each available in light and dark variants:
- Stockholm (
stockholm-light.css&stockholm-dark.css) - Svalbard (
svalbard-light.css&svalbard-dark.css) - Visby (
visby-light.css&visby-dark.css) - Material3 (
material3-light.css&material3-dark.css) - Fluent2 (
fluent2-light.css&fluent2-dark.css)
The CSS is located in the /build folder of the Bryntum distribution. You can include it in your project by for example
using link tags:
<!-- Structural CSS -->
<link rel="stylesheet" href="build/scheduler.css">
<!-- Bryntum theme -->
<link rel="stylesheet" href="build/svalbard-light.css" data-bryntum-theme>
The data-bryntum-theme attribute on the link tag is not strictly required, but it allows you to programmatically
switch the theme at runtime using DomHelper.setTheme().
Comparison of themes
Svalbard
Our default theme, very light and minimalistic. It is designed to be easy on the eyes and to not distract from the data.
![]()
Stockholm
The Stockholm theme was our default theme prior to v7.0. It has been updated with a more modern look and feel.
![]()
Visby
The city of Visby is famous for its medieval city wall, and the Visby theme embraces that by using more borders than our other themes.
![]()
Material3
The Material3 theme is based on Google's Material Design. It is a modern and clean theme that is slightly more colorful than our Svalbard theme.
![]()
In most of the included examples you can switch theme on the fly by clicking on the gear icon found in the header and then picking a theme in the dropdown.

Combining products
The structural CSS described above include all the CSS you need to use Scheduler and its helper widgets such as Popups, TextFields and so on. When combining multiple different Bryntum products on a single page using normal structural CSS, the shared styling will be included multiple times.
To avoid this, each product's structural CSS is available in a version that only contains the CSS specific for that
product. These are called thin CSS bundles (e.g. scheduler.thin.css).
When using them you will need to include one for each used level in the Bryntum product hierarchy
(Scheduler -> Core + Grid + Scheduler).
For example to combine Calendar and Scheduler using the Svalbard Light theme, you would include:
core.thin.cssgrid.thin.cssscheduler.thin.csscalendar.thin.csssvalbard-light.css
Which in your html file might look something like this:
<link rel="stylesheet" href="core.thin.css" >
<link rel="stylesheet" href="grid.thin.css">
<link rel="stylesheet" href="scheduler.thin.css">
<link rel="stylesheet" href="calendar.thin.css">
<link rel="stylesheet" href="svalbard-light.css" data-bryntum-theme>
Nothing prevents you from always using thin CSS bundles, but please note that there might be a slight network overhead from pulling in multiple CSS files as opposed to a single one with the normal CSS.
Creating a custom theme
To create your own theme, get the distribution bundle or install the NPM package as usual and follow these steps:
- (Optional) Make a copy of an existing theme found under
build/(either in package under thenode_modulesfolder or in the extracted zip), for example thesvalbard-light.cssfile. If you pick the theme that is closest to what you want, you will have to change less. You can also start from scratch, but it will be more work. - Edit the variables in it to suit your needs, and add any additional variables you want to tweak. You can reference all
the available variables in the API documentation for each widget, or by looking at the CSS files in the
libfolder. - Include your theme on page (and remove any default theme you where using).
Depending on the import order of your CSS files, you might need to make the theme's variables more specific than the structural CSS. If for example this does not alter the variables as you would expect:
:root {
--b-button-outlined-border-color : lightsalmon;
}
It might be because the structural CSS is included after your theme, and it sets the variable to a different value. In that case, you can either alter the inclusion order (if you have control over the build process), or make your variables more specific:
/* The :not rule can contain anything, its purpose is only to make this rule */
/* more specific */
:root:not(.b-nothing) {
--b-button-outlined-border-color : lightsalmon;
}
/* Another (less flexible) option is to scope it to a specific selector */
.b-button {
--b-button-outlined-border-color : lightsalmon;
}
Scheduler also uses variables from grid-sass, found at node_modules/@bryntum/scheduler/source/resources/grid-sass/variables.scss
Please see the Custom theme example for a custom theme in action:
![]()
Overriding an existing theme
As an alternative to creating a full custom theme, you can also just override a few variables in an existing theme. To do so, include the structural CSS and the theme you want to use, and then add your own CSS file that overrides the variables you want to change.
<!-- Structural CSS -->
<link rel="stylesheet" href="build/scheduler.css">
<!-- Bryntum theme -->
<link rel="stylesheet" href="build/svalbard-light.css" data-bryntum-theme>
<!-- Your customizations -->
<link rel="stylesheet" href="path/to/your/customizations.css">
In customizations.css, you can then override any variables you want to change:
:root {
/* Everything looks good in lightsalmon */
--b-button-outlined-border-color : lightsalmon;
}
Switching theme at runtime
You can also add a combo box (or other UI) that lets you change the theme at run-time, similar to the examples we have.
To do so, ensure you have multiple themes in a folder (e.g. /themes).
If you're using custom themes, ensure that you change their names in the .b-theme-info block in the CSS file to avoid
collisions.
Next, you need to add a combo box using tbar.
import { Scheduler, DomHelper } from '@bryntum/scheduler';
const scheduler = new Scheduler({
// ...scheduler data
tbar : [
{
type : 'combo',
// list of themes shown in the drop down (combo box)
items : [
{ text : 'Svalbard Light', value : 'svalbard-light' },
{ text : 'Svalbard Dark', value : 'svalbard-dark' },
{ text : 'Visby-Light', value : 'visby-light' },
{ text : 'Visby-Dark', value : 'visby-dark' }
// More themes...
],
label : 'Theme',
// default theme
value : 'svalbard-light',
// change theme on selection
onAction(props) {
DomHelper.setTheme(props.value);
}
}
]
});
With that being set up, you can switch themes within your application.
Customizing the event bar HTML contents
It is easy to show any HTML structure inside an event bar using the eventRenderer.
const scheduler = new Scheduler({
appendTo : 'container',
columns : [
{ text : 'Name', field : 'name' }
],
eventRenderer : ({ eventRecord, renderData }) => {
const value = eventRecord.percentDone || 0;
// Add an extra element to the children of the container, to display a progress bar.
// In a real app, you should avoid having inline styles and instead style using the CSS class
renderData.children.push({
text : `${eventRecord.name} ${value}%`,
className : 'percentBar',
style : {
position : 'absolute',
width : `${value}%`,
height : '100%',
display : 'flex',
'background-color' : 'rgba(255, 255, 255, 0.25)',
'padding-left' : '1em',
'align-items' : 'center'
}
});
}
});
//<code-header>
fiddle.title = 'Event renderer';
//</code-header>
const scheduler = new Scheduler({
appendTo : targetElement,
autoHeight : true,
rowHeight : 70,
columns : [
{ text : 'Name', field : 'name', width : 160 }
],
resources : [
{ id : 1, name : 'Johnny' },
{ id : 2, name : 'Britney' },
{ id : 3, name : 'Lazy Dave' }
],
events : [
{
resourceId : 1,
startDate : '2017-01-02',
endDate : '2017-01-07',
name : 'Prepare Meeting',
percentDone : 40
},
{
resourceId : 2,
startDate : '2017-01-02',
endDate : '2017-01-07',
name : 'Conference',
percentDone : 80,
eventColor : 'green'
},
{
resourceId : 3,
startDate : '2017-01-02',
endDate : '2017-01-07',
name : 'Happy hour',
percentDone : 20,
eventColor : 'blue'
}
],
startDate : new Date(2017, 0, 1),
endDate : new Date(2017, 0, 14),
eventRenderer : ({ eventRecord, renderData }) => {
const value = eventRecord.percentDone || 0;
renderData.children.push({
className : 'percentBar',
style : {
position : 'absolute',
width : `${value}%`,
height : '100%',
display : 'flex',
'background-color' : 'rgba(0,0,0,0.2)',
'padding-left' : '1em',
'align-items' : 'center'
},
text : `${eventRecord.name} ${value}%`
});
}
});Controlling output using column renderers, event renderer and CSS
Contents of grid cells, header cells and events can be fully customized using 'renderers'. Renderers are functions with access to a the data used output grid cells / header cells / events (such as style and CSS classes, and in some cases elements). They can manipulate the data to alter appearances or return a value to have it displayed.
In the demo below, we use the following APIs:
- Resource
clsfield - To provide row specific styling - Column cell renderer - To output custom cell content
- Column header renderer - To add special text in column header
- Time Axis cell renderer - To show a sad emoji on the most boring day week of the day (Monday)
- Event bar renderer - To output custom text into the event bar
//<code-header>
fiddle.title = 'Renderers';
//</code-header>
const scheduler = new Scheduler({
appendTo : targetElement,
autoHeight : true,
rowHeight : 50,
viewPreset : {
base : 'weekAndDayLetter',
headers : [
{
unit : 'week',
dateFormat : 'ddd DD MMM YYYY' // Mon 01 Jan 2017
},
{
unit : 'day',
renderer : (start, end, headerConfig, index) => {
if (start.getDay() === 1) {
headerConfig.headerCellCls = 'blue-monday';
return '☹️';
}
return DateHelper.format(start, 'd1');
}
}
]
},
columns : [
{
text : 'Name',
field : 'name',
width : 160,
htmlEncode : false,
headerRenderer({ column }) {
return column.text.toUpperCase() + '!';
},
renderer({ record, value }) {
return `<i class="fa fa-${record.gender}"></i>${value}`;
}
}
],
resources : [
{ id : 1, name : 'Hercule', gender : 'male' },
{ id : 2, name : 'Agatha', gender : 'female' },
{ id : 3, name : 'Ben (on vacation)', gender : 'male', cls : 'unavailable' },
{ id : 4, name : 'Dorothy', gender : 'female' }
],
events : [
{ resourceId : 1, startDate : '2017-01-01', endDate : '2017-01-10', name : 'Meeting', iconCls : 'fa fa-calendar' },
{ resourceId : 2, startDate : '2017-01-02', endDate : '2017-01-09', name : 'Conference', iconCls : 'fa fa-wine-glass' }
],
startDate : new Date(2017, 0, 1),
endDate : new Date(2017, 0, 10),
eventRenderer({ eventRecord, renderData }) {
renderData.style = 'font-weight: bold; border-radius: 3px';
return 'Activity: ' + eventRecord.name;
}
});const scheduler = new Scheduler({
viewPreset: {
base : 'weekAndDayLetter',
headers : [
{
unit : 'week',
dateFormat : 'ddd DD MMM YYYY', // Mon 01 Jan 2017
},
{
unit : 'day',
renderer : (start, end, headerConfig, index) => {
if (start.getDay() === 1) {
headerConfig.headerCellCls = "blue-monday";
return '☹️';
}
return DateHelper.format(start, 'd1');
}
}
]
},
columns : [
{
text : 'Name',
field : 'name',
width : 160,
htmlEncode : false,
// Custom header renderer
headerRenderer : ({ column }) => column.text.toUpperCase() + '!',
// Custom cell renderer
renderer({
record,
value
}) {
return `<i class="fa fa-${record.gender}"></i>${value}`;
}
}
],
// Custom event renderer, simple version
eventRenderer({
eventRecord,
tplData
}) {
// Inline style
tplData.style = 'font-weight: bold; border-radius: 3px';
// Add CSS class
tplData.cls.add('my-custom-css');
// Return the text to display
return 'Activity: ' + eventRecord.name;
}
});
Styling dependency lines
You can easily customize the arrows drawn between events when using the Dependencies feature. To change all arrows, apply the following basic SVG CSS:
.b-sch-dependency {
stroke-width : 2;
stroke : red;
}
.b-sch-dependency-arrow {
fill : red;
}
To style an individual dependency line, you can provide a cls in your data:
{
"id" : 9,
"from" : 7,
"to" : 8,
"cls" : "special-dependency"
}
// Make line dashed
.b-sch-dependency {
stroke-dasharray : 5, 5;
}
Other useful configs
There are a few other configs worth mentioning to affect the styling of your Scheduler/events:
barMargin, distance between overlapping events within a resource (docs) (demo)resourceMargin, distance between the first and last event and the resources borders (docs) (demo)eventLayout, determines if overlapping events stack, pack or simply overlap (docs) (demo)
const scheduler = new Scheduler({
barMargin : 3,
resourceMargin : 15,
eventLayout : 'pack',
/*...*/
});
Happy styling :)
Troubleshooting
CSS mismatched version
If you've encountered a CSS error:
CSS version 7.0.0 doesn't match bundle version 7.2.0-alpha-1!
Make sure you have imported css from the appropriate product version.
That means you're using a wrong version of Bryntum theme file. Following are some of the ways to check and fix the issue:
Verify CSS version
Ensure that the CSS file being used matches the version of the Bryntum API. For example, if you're using version
7.2.0-alpha-1 of Scheduler, you need to have the CSS files of version 7.2.0-alpha-1.
Clear Cache
Ensure the mismatched CSS file is not cached on your web server to prevent outdated files from being served. Clear the browser cache to ensure the latest CSS file is loaded.
Cache Busting
Cache busting is a technique used to force browsers to load the most recent versions of files. If the CSS file is
imported in index.html, then it should have cache busting by specifying the version
(scheduler.css?v=7.2.0-alpha-1) or use timestamps (scheduler.css?1704085200).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Scheduler App</title>
<link rel="stylesheet" href="path/to/stylesheet.css?v=1.2.3"> <!-- Cache busting by specifying version -->
</head>
<body>
<!-- Your content here -->
</body>
</html>
Modern frameworks apply this by default to the production code, but it needs to be manually implemented in vanilla JavaScript projects.