Skip to content

Theming

Element provides a default element theme with light and dark theme types as well as supports the definition of custom themes. A custom theme can support either light, dark, or both theme types.

How it works

Element uses CSS variables to implement theming, as they can be changed at runtime in the browser without page reload. The semantic color tokens in the design system are set to CSS variables instead of direct color codes, e.g. $element-ui-0: var(--element-ui-0); and are changed at runtime by either applying the .app--dark CSS class or by changing the value using the service SiThemeService.

The SCSS variables are also set or overwritten to use those semantic tokens including the base font. Besides that, assets like the brand logo can also be overwritten using CSS variables.

Dark mode

Element supports a light and dark theme mode, which applies to the theme itself as well as all components. A user can choose either light or dark mode, while the default is being derived from the browser or operating system configuration.

Applying dark mode

Switching dark mode is done by adding the class app--dark to the <html> tag. This will then switch the CSS variables to the value for the dark theme.

This process is automated using the SiThemeService service. Inject the service in your component and use applyThemeType('dark' | 'light' | 'auto'):

Note: It is recommended to call themeService.applyThemeType('auto') during initialization of the app (e.g. within app.component.ts) as this derives the theme choice from the user's browser or operating system configuration, allowing a coherent experience across different apps.

Preparing application for dark mode support

The dark theme works out of the box, if you use the semantic tokens and follow these few steps:

  • In the application's SCSS, make sure to use the semantic tokens everywhere, i.e. use $element-ui-4 for border colors instead of $element-gray-200.

  • In some cases using the $element-ui-* tokens will fails, e.g. for things like background-color: rgba($element-ui-4, 0.5).

Custom themes

The SiThemeService is responsible for all theming topics.

  • At startup, it tries to load a custom active theme from the SiThemeStore.
  • If available, it applies the custom theme. Otherwise, the default Element theme is used.
SiThemeStore object is used by the theme service to load and store the themes. You can inject your own implementation to provide a backend implementation. Otherwise a localStorage based implementation is used.
Constructor
() => {}
Methods
Sets the theme with the given name to active.
Returns True on success, otherwise false.
Parameters
The name of the theme to become active.
name: string
Deactivate any active theme and makes the element theme the default one.
Returns True on success, otherwise false.

deactivateTheme: () => Observable<boolean>
Deletes the theme with the given name from the store.
Returns True on success, otherwise false. All nicely wrapped in an observable that may also emit errors. Returns false, if the theme does not exist.
Parameters
The name of the theme to be deleted.
name: string
Load and return an alternative custom theme, other then the default element theme. This method is invoked initially to check for an alternative custom theme.
Returns The active theme to be used, or undefined if the default element theme shall be used. All wrapped in an observable that can also emit errors.

loadActiveTheme: () => Observable<(undefined | Theme)>
Load theme with the given name .
Returns Observable with the named theme or undefined if no such theme exist.
Parameters
The name of the theme to be returned.
name: string
Load and return the available theme names.
Returns An Observable of available theme names, other than the default element theme.

loadThemeNames: () => Observable<string[]>
Saves a theme to the store. The name shall not be empty. A theme with identical name gets overwritten.
Returns True on success, otherwise false. All nicely wrapped in an observable that may also emit errors.
Parameters
The theme to be saved.
theme: Theme

The SiDefaultThemeStore is a localStorage based implementation of the SiThemeStore, which is used by default. To provide custom themes using other means than a localStorage like e.g. a backend service, you can implement your own SiThemeStore and load a Theme custom theme object.

You need to provide your implementation in the main app module:

{ provide: SiThemeStore, useClass: YourThemeStoreImpl }

SiThemeService API Documentation

provided in root

Attributes and Methods

NameTypeDefaultDescription
activeThemeName
Optional
stringThe name of the theme that is active. Theme name element is the default.
addOrUpdateTheme(...)
(theme: Theme) => Observable<boolean>Adds or updates the given theme in the theme store.
Returns true if the theme was saved successfully.

Parameters
  • theme: Theme  The theme to be saved.
applyTheme(...)
(theme: Theme, type: ThemeType, overwrite: boolean) => voidApplies the given theme to the document. If no theme is given, the active theme is applied.

Parameters
applyThemeType(...)
(type: ThemeType) => voidApply light or dark theme to the document.

Parameters
deleteTheme(...)
(name: string) => Observable<boolean>Deletes the theme with the given name from the theme store.

Parameters
getActiveTheme()
() => Observable<(undefined | Theme)>Loads and returns the currently active theme. Returns undefined if no custom theme is used.
Returns A custom theme or undefined if the default element theme is used.
getTheme(...)
(name: string) => Observable<(undefined | Theme)>Returns a clone of the theme with the given name or undefined if not available or name is element .
Returns The theme with the given name and undefined if name is element .

Parameters
  • name: string  The name of the theme to be returned.
hasTheme(...)
(name: string) => booleanReturns true if a theme with the given name is available.

Parameters
isThemeValid(...)
(data: unknown) => booleanChecks if the given theme JSON object is a valid theme.

Parameters
resetPreview()
() => voidResets the preview theme to the default element theme.
(readonly) resolvedColorScheme
(undefined | ThemeType)The current color scheme. (e.g. light or dark).
(readonly) resolvedColorScheme$
Observable<keyof ThemeColorSchemes>this.resolvedColorSchemeSub.asObservable()Emits events when the color scheme changes.
setActiveTheme(...)
(name: string, type: ThemeType) => Observable<boolean>Sets the active theme to the given name. If no name is given, the default element theme is used.

Parameters
(readonly) themeChange
EventEmitter<(undefined | Theme)>...Emits events when the currently applied theme changes. Either by changing to another theme or by re-applying a theme with updated properties. When switching to default theme element, undefined is emitted.
(readonly) themeIcons
WritableSignal<Record<string, SafeHtml>>{}Icon overrides by the currently activeTheme.
(readonly) themeNames
string[]All available theme names, including element theme name.
(readonly) themeNames$
Observable<string[]>this.themeNamesSub.asObservable()Emits events when the list of available theme names changes.
updateProperty(...)
(name: string, value: string, type: keyof ThemeColorSchemes) => voidUpdates the given property of the preview theme.

Parameters

Build time custom theme

It's also possible to use custom themes at build time. This option is mostly for OEM theming. To use a theme at build time, first set up a SCSS file with the theme definitions. These are a SCSS map. For the required keys, please see the the Siemens Brand definitions.

For example, create _theme-oem.scss with this:

$theme-oem: (
  // definitions, see above
);

Then, to include this theme and build it as the default, change the main style sheets:

// first configure the element-theme by not building the 'siemens-brand' theme
@use '@siemens/element-theme/src/theme' with (
  $element-theme-default: 'oem', // the default is 'siemens-brand';
  $element-themes: ('oem'), // themes to build.
);
@use '@siemens/element-ng/element-ng';

// build the OEM theme
@use '@siemens/element-theme/src/styles/themes';
@use './theme-oem';
@include themes.make-theme(theme-oem.$theme-oem, 'oem', false);

The list $element-themes doesn't need to include the value set as $element-theme-default. $element-theme-default determines the name of the theme used as default, i.e. the one that is active w/o setting any additional class on the root element.

To use e.g. the siemens-brand theme by default but also allow a oem theme as opt-in, use $element-theme-default: 'siemens-brand' or completely emit this configuration and provide $element-themes: ('oem'). The additional oem theme is built and can be activated by applying the class theme-oem to the <html> tag.

If both a light and a dark mode version are desired, defines two maps, e.g.

$theme-oem-light: (
  // light mode and shared definitions
);

$theme-oem-dark: (
  // dark mode definitions
);

Then, use themes.make-theme() like this:

@include themes.make-theme(theme-oem.$theme-oem-light, 'oem', false);
@include themes.make-theme(theme-oem.$theme-oem-dark, 'oem', true);

Important info

The required keys in the map might change in future versions of Element, so forward compatibility is not guaranteed. Topic like usability and accessibility and not guaranteed that way so please always involve UX when using this feature.

Types Documentation

Properties
dark?: ThemeColorScheme
light?: ThemeColorScheme
Properties
A map of icons that overrides the default Element icons. The key must be the key of the original icon that should be overridden. The value has to be a data SVG string.

Example:
{
  elementUser: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'>...</svg>"
}
icons?: Record<string, string>
name: string
schemes: ThemeColorSchemes
("dark" | "light" | "auto")

Except where otherwise noted, content on this site is licensed under MIT License.