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. withinapp.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 likebackground-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. | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||
|
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¶
Attributes and Methods¶
Name | Type | Default | Description |
---|---|---|---|
activeThemeName | string | The 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
| |
applyTheme(...) ¶ | (theme: Theme , type: ThemeType , overwrite: boolean ) => void | Applies the given theme to the document. If no theme is given, the active theme is applied. Parameters | |
applyThemeType(...) ¶ | (type: ThemeType ) => void | Apply 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
| |
hasTheme(...) ¶ | (name: string ) => boolean | Returns true if a theme with the given name is available.Parameters
| |
isThemeValid(...) ¶ | (data: unknown ) => boolean | Checks if the given theme JSON object is a valid theme. Parameters
| |
resetPreview() ¶ | () => void | Resets 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 ) => void | Updates 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¶
|
|
Except where otherwise noted, content on this site is licensed under MIT License.