Theming
Many applications aim to provide multiple themes, especially light and dark modes to support user preferences. GoJS provides functionality to define and manage themes to achieve this goal.
Getting started with themes
Various GoJS templates are themed, such as the default node, group and link template, tool adornments, background grid, and more. This makes it easy to quickly change the way certain objects appear. For example, you can change the selection adornment color/thickness without providing a Part.selectionAdornmentTemplate, or change the temporary link color when drawing a new link without providing a LinkingBaseTool.temporaryLink.
The default theme objects group properties into category objects by property type. The category for a given
binding is inferred from the target property. For example, Shape.fill and
Shape.stroke are grouped in the colors object, while Shape.strokeWidth is
grouped in numbers. The predefined templates and tool archetypes use the following categories:
| Category | Used for | Example keys |
|---|---|---|
colors |
brush-valued properties such as Shape.fill and Shape.stroke | selection, tempLink, link, text |
fonts |
font strings for TextBlock.font | normal, bold |
numbers |
numeric properties such as Shape.strokeWidth | selection, group |
margins |
Margin-valued properties such as Panel.padding | group |
arrowheads |
arrowhead names for Shape.toArrow and Shape.fromArrow | toArrow |
For a complete list of themed properties on predefined templates, see Templates.js in the extensionsJSM directory.
Basic theming
The simplest way to theme your diagram is to use the predefined Themes available and call GraphObject.theme or create a new ThemeBinding when constructing templates. By default, both a light and a dark theme are provided in the ThemeManager. These are the Themes.Light and Themes.Dark objects, respectively.
To change themes, simply set ThemeManager.currentTheme to a theme name.
Note that the special value 'system' will pick either the
'light' or 'dark' theme depending on the end user's browser preference.
Creating or modifying themes
In most scenarios, you'll want custom themes, either by modifying the predefined themes or creating your own.
This can be done by calling ThemeManager.set, passing a theme name and a partial (or complete) Theme object.
Passing an empty string as the theme name will modify the ThemeManager.defaultTheme, which is initially 'light'.
If the theme name exists in the ThemeManager.themeMap, that theme will be updated by merging the partial theme object into it. If the theme name does not exist, the theme will be added to the theme map.
Using CSS variables for theming
If you're using CSS variables to style other parts of your application, you can use ThemeManager.readsCssVariables to reuse those variables in your GoJS themes.
NOTE: The syntax to reference a CSS variable in a theme is 'var(<varname>)'.
Only a single variable may be referenced, and any fallbacks should be defined either on the template or
in the referenced CSS variable.
The CSS variable's value will be read before any Binding.themeConverter functions have run.
In some cases, your CSS variables may already handle light and dark mode. If that's the case, you have the option to use a single theme which references those variables. Rather than changing the theme, you'll update your page as normal and call ThemeManager.updateDiagrams, reflecting any changes in CSS variables in the ThemeManager's associated diagrams.
When using a single theme, you'll need to make sure you define any properties used
by default templates such as colors.selection or colors.link
if you haven't overridden those templates.
Theme binding sources
The typical case for theming a GraphObject will be getting a value directly from a Theme. It is also possible to use values from other sources, such as a bound data object, a GraphObject in the binding Panel, or the shared model data object.
These different sources are specified by calling GraphObject.themeData, GraphObject.themeObject, or GraphObject.themeModel. In addition to specifying the source, the Binding.converter function can be used to convert from some value to a theme property name. In the following example, a themeObject binding is used on the node's text to get a color variable from the theme when the node is selected:
Converting theme values
In addition to a conversion function to determine the theme property name, a Binding.themeConverter can be provided as the fifth argument to GraphObject.themeData to perform a conversion on the resulting theme value before assigning it to the target property.
Other themable types
Discussion on this page has focused on colors, but theming can also be used for fonts, stroke widths, sizes, or any other property type. You must ensure that the returned theme value matches the type of the target property.
To access an arbitrary property value in your theme, you can use a '.' separated path,
like 'colors.primary' or 'icons.mode'.
Theming builder objects
To keep the builder objects ("Button", "ToolTip", "ContextMenu", etc) simple, they are not themed by default.
Creating themed versions of these objects is relatively simple given the predefined definitions available at Buttons.js. Here we demonstrate theming the "Button" and "ToolTip" builders.
See the learn pages on buttons, tooltips, and context menus to change appearances without theming.