How theme works
The theming system in Experience Builder provides you the power to systematically customize the look-and-feel of your apps. Experience Builder provides a default theme with configurable attributes called theme variables and style modules for the UI components from Jimu UI. Under the hood, the style modules read the theme variables and use them to generate CSS styles at runtime and apply them to components accordingly.
All themes are customized and extended from the default theme.
A specific theme usually consists of the following:
- theme variable overrides: colors, typography, spacings, components, etc. provided in a JSON file.
- style overrides: either a Sass file(.scss) or a TypeScript file(.ts)
- supporting assets: fonts, images, etc.
Theme variables
Theme variables are the configurable attributes that the components use to style themselves with.
Core variables
- Colors:
- primary: used to present primary UI elements, show active states, or interactive sections
- secondary: used to present secondary UI elements
- info: used to present general information
- success: used to present a success state, such as completion of a process or passing a successful check
- warning: used to present an in-progress state or warning information that the users should be noticed
- danger: used to present a failed state or a severe situation that the users should be aware of
- light: mostly used to present the background and border of layout elements, such as containers and separators
- dark: mostly used to present text elements
- black
- white
- All the above theme colors, except black and white, also have nine different shades (from 100 to 900)
- Typography: font family, font sizes, font weights, and line heights
- Spacing:
- sizes: used to define margins and paddings
- gutters: used to define small spaces, for example, space between an icon and text within a button
- Border: the default border color and width
- Border radius: none, sm, default, lg, circle, and pill
- Box shadows: none, sm, default, lg
Component variables
- Body: color and font definition to be applied to the
body
section - Header: Background and color definition to be applied to the
header
section - Footer: Background and color definition to be applied to the
footer
section - Link: color definition to be applied to the
<a
tags> - All the other UI components: Button, Dropdown, Nav, Modal, etc.
See the full theme variable JSON from the demo theme.
These variables are defined in a JSON format and can be overridden by a custom variables.json
file.
How to create a theme
There are two approaches to create a new theme:
- Override the default theme variables
- Provide extra style modules or stylesheets
Normally, providing variable overrides should be sufficient and it is the easiest. Only consider the second approach if your theme design cannot be achieved by redefining variables and customize CSS styles are needed, for example, to provide a unique look-and-feel for a certain component.
Override theme variables
This is the easiest and most common approach to define your own theme in Experience Builder.
First, let's create a new folder under client/your-extensions/themes/
directory with
the following structure:
- variables.json: where the custom theme variables will go to
- thumbnail.png: the thumbnail of the theme
- manifest.json: view
jimu-core/lib/types/manifest.d.ts
for the list of properties
Open variables.json
and add your custom overrides such as:
{
"colors": {
"primary": "red"
},
"typography": {
"fontFamilyBase": "Impact, Arial",
"fontSizeBase": "1rem"
}
}
Re-run npm start
in the client directory in your command prompt or terminal window to
have Experience Builder pick up the new theme.
Override CSS styles
If you would like to provide additional CSS styles to your theme, or use CSS to override existing
styles that simply overriding theme variables cannot achieve, you can do so by adding a style
file
to the theme.
The style
file can have two different extensions (representing two different ways of writing styles):
.ts
(recommended): uses the CSS-in-JS way to provide scoped CSS styles.scss
: the more "traditional" way of directly writing static CSS styles, with extra abilities offered by the Sass library.
Note: only one style file can be added to a theme folder.
style.ts
This refers to the use of the CSS-in-JS (Emotion library) method to provide scoped CSS styles to re-style components in your theme. Global styles are also considered as a special style module in the theming system.
The reasons that using CSS-in-JS is recommended are as follows:
- Full access to the theme variables in a JSON structure from the code
- The styles are scoped and targeted to certain components, making the style management more controlled
Example: re-style the Button component
First, create a style.ts
file in the theme folder, and add the following required import
to the file:
import { css } from 'jimu-core';
Then we can start writing custom style modules for the target components by using the 'css' prop from Emotion.
Create a function with css prop as the returned value:
import { css } from 'jimu-core';
// custom styles applied to the Button component from Jimu UI:
const customButtonStyles = (props) => {
return css`
/* put your CSS here */
`;
}
Optionally, you can call props.theme
to get the theme variables from the props
parameter,
as well as other props available from the target component.
Put any of your CSS styles for the component inside of css` `:
import { css } from 'jimu-core';
// custom styles applied to the Button component from Jimu UI:
const customButtonStyles = (props) => {
const theme = props.theme;
const buttonType = props.type;
return css`
/* make the primary button's text to be bold and has a shadow */
${buttonType === 'primary' && `
font-weight: ${theme.typography.weights.bold};
box-shadow: ${theme.boxShadows.default};
`}
`;
}
Last step, export the function as a module renamed to the name of the component:
// at the end of the style.ts file:
export { customButtonStyles as Button};
Example: global styles
Create another function with css prop as the returned value:
import { css } from 'jimu-core';
// global styles applied to the entire app:
const customGlobalStyles = (props) => {
return css`
/* make the root font size smaller */
html {
font-size: 80%;
}
`;
}
Global style module can be exported with the name 'Global':
// at the end of the style.ts file:
export { customGlobalStyles as Global};
At runtime, Jimu's theme manager will load these extra styles along with the default one and apply them together to the components.
style.scss
This refers to the "traditional" way of writing styles in static CSS.
In the theme folder, you can optionally add a style.scss
file to define your custom CSS with.
In the runtime, this file will be imported last and will override all the other styles,
such as the styles generated from variables.json.
Quick sample:
body {
background: #333;
color: white;
font-family: Impact, Arial;
}
.btn {
background: red;
}
Other helpful tips
Use custom fonts
Experience Builder allows custom fonts to be added to a theme.
The custom fonts can be files hosted on a server, such as Google Fonts, or local ones inside of
the theme folder, such as path/to/your-theme/assets/fonts/
.
Import fonts
If the font set comes with a font CSS file, then the font can be imported as such:
Using style.ts
:
import { css } from 'jimu-core';
// add font import to the global style function:
const customGlobalStyles = (props) => {
return css`
/* import Open Sans font */
@import url('https://fonts.googleapis.com/css?family=Open+Sans');
`;
}
export { customGlobalStyles as Global};
Using style.scss
:
/* import Open Sans */
@import url('https://fonts.googleapis.com/css?family=Open+Sans');
Apply custom fonts
Configure the font
attribute in variables.json
:
{
"typography": {
"fontFamilyBase": "Open Sans"
}
}