Edit page

Theming

From the very beginning, React UI has been designed with a great emphasis on customizability. We decided to leverage CSS custom properties for this feature for two main reasons:

  1. We take advantage of possibilities of native CSS. Preprocessors are still a thing, but it's not necessary to go as far as for CSS-in-JS to make a UI customizable.

  2. Thanks to its JavaScript API, CSS custom properties are both readable and writable by JS.

Theming Options

CSS custom properties are used to define common visual properties like colors, fonts, borders, shadows, or spacing. They come prefixed with rui- so they don't get in way of other custom properties in your project.

Theming options come grouped into three sections according to what they describe:

  1. design tokens,
  2. layout components,
  3. UI components.

You can adjust any of these options in your styles. See the default theme for the full list of available settings.

Design Tokens

Design tokens are special variables that define the smallest pieces of a design language, especially colors, typography, or spacing.

Design token names shouldn't be complex nor long so they are simply lowercase and hyphenated:

:root {
--rui-spacing-0: 0;
--rui-spacing-1: 0.25rem;
--rui-spacing-2: 0.5rem;
--rui-spacing-3: 0.75rem;
--rui-spacing-4: 1rem;
--rui-spacing-5: 1.5rem;
--rui-spacing-6: 2rem;
--rui-spacing-7: 3rem;
}

️👉 Please note that breakpoint values are exported as read-only since CSS custom properties cannot be used within media queries (because media query is not a CSS property).

Layouts and UI Components

It is also possible to adjust some properties on individual components level, preferably by reusing design tokens.

Layouts and UI component names use naming convention that is familiar to many web developers because it looks like BEM (or SUIT CSS, more precisely):

--rui-<ComponentName>--[<modification(s)>]__[<element>]--[<modification(s)>]__<property>--[<modification>]

Where:

  • <ComponentName> stands for actual component name (e.g. Button, FormField etc.) with a reasonable exception to form fields whose settings are widely shared and therefore grouped as FormField options.
  • <modifications(s)> can be one or more modifiers, typically a variant (e.g. primary, filled, box) or interaction state (default, hover, focus, active, disabled).
  • <element> stands for a nested element of the component.
  • <property> is usually a CSS property (e.g. color, background, background-color, width, box-shadow), or a brief property description where a CSS property wouldn't tell enough (e.g. initial-offset, check-background-color, tap-target-size).

Example component theming options:

:root {
--rui-Button--filled--primary--default__color: var(--rui-color-on-primary);
--rui-Button--filled--primary--default__border-color: var(--rui-color-primary);
--rui-Button--filled--primary--default__background: var(--rui-color-primary);
--rui-Button--filled--primary--default__box-shadow: none;
--rui-Button--filled--primary--hover__color: var(--rui-color-on-primary);
--rui-Button--filled--primary--hover__border-color: var(--rui-color-primary-dark);
--rui-Button--filled--primary--hover__background: var(--rui-color-primary-dark);
--rui-Button--filled--primary--hover__box-shadow: none;
}

CSS, or SCSS?

Colors, breakpoints, and SVG definitions used in theme.scss are preprocessed with SCSS first. This enables us to:

  • generate color palette programmatically,
  • keep actual breakpoint values in a single place in the code,
  • keep theme.scss uncluttered by inline SVG.

It's entirely up to you what format you decide to use for storing the theme. Both theme.scss and theme.css will work equally well, it only matters if the custom properties make it from the theme file to browser.

👉 Just remember everything in the theme constants directory is intended only for usage within theme.scss. Otherwise, the theming system may not work as expected. We recommend calling custom properties from theme.scss either directly in your stylesheet, or through an intermediate, shareable layer like MyComponent/_theme.scss or styles/shared-by-components/_my-sass-variables-referring-to-theme.scss (latter of which is the approach we use).

Best Practices

It's a good idea to start with changing design tokens first. Widely reused settings such as colors, typography, borders, or spacing values should be adjusted first because they define basic appearance of all components.

Having finished the customization at the global level, you can then proceed to customizing the appearance of individual components — if necessary at all. Even then you should also reuse existing design tokens as much as possible to ensure that your UI is consistent and works as a system.

For the same reason, if you have any custom components in your UI, you should reuse design tokens in your own CSS too.