A theme is a coherent style applied on UI components. Themes make it easier to customize your app's design for a specific brand or app state (for example, 'light mode' and 'dark mode').
Head to this demo scope to see the full example of the theming solution.
A theme needs a theme provider to apply the same style values on multiple UI components. Run the following to create a new component that will later be used as a theme-provider for your components:
To create your basic or default theme, start by composing a list of design tokens. These are pairs of style attributes and values which represent all design decisions.
Add a design-tokens.ts
file to your component, to place your design tokens:
/** @filename: my-theme/design-tokens.ts */ export const defaultDesignTokenValues = { primaryColorBackground: '#568cb0', primaryColorText: '#ebebeb', mediumFontSize: 25, buttonPaddingMedium: '1rem', buttonFontWeight: 700, };
Design tokens are usually maintained in a JSON format, to make them compatible across a wide range of technologies.
Run the following to install Bit's theme-provider generator:
Use the createTheme
function, to generate a new theme-provider that uses your design tokens:
import { createTheme } from '@teambit/base-react.theme.theme-provider'; /* import the default tokens from the file generated in the previous step */ import { defaultDesignTokenValues } from './design-tokens'; /* generate a theme using the design token default values */ export const MyTheme = createTheme({ theme: defaultDesignTokenValues, }); /* create a theme schema to standardize future theme extensions */ export type MyThemeSchema = typeof defaultDesignTokenValues;
Make MyTheme
and the MyThemeSchema
type alias available to other components by exporting them from your component's index.ts
file:
export { MyTheme } from './theme-provider'; export type { MyThemeSchema } from './theme-provider';
The theme provider provides two methods of theming:
- Theming components using a React Context that provides the right values to the components' JS variables that are used for styling
- Theming components using CSS custom props (in this case, it only has to make the custom CSS props available in the page)
Theme React components using Context
Use the useTheme
hook provided by your newly-generated theme-provider, to set the right values for your component styling. For example:
import type { CSSProperties } from 'react'; import { MyTheme } from '@my-org.my-scope/my-theme'; const Button = ({ children }) => { const { primaryColorBackground, primaryColorText, buttonPaddingMedium, buttonFontWeight, } = MyTheme.useTheme(); const style: CSSProperties = { backgroundColor: primaryColorBackground, color: primaryColorText, padding: buttonPaddingMedium, fontWeight: buttonFontWeight, }; return <button style={style}>{children}</button>; };
Wrap you components with the Theme context (provided by your theme-provider):
import { MyTheme } from '@my-org.my-scope/my-theme';
import { Button } from '@my-org.my-scope/button';
() => (
<MyTheme.ThemeProvider>
<Button>I'm a themed button!</Button>
</MyTheme.ThemeProvider>
)
Theme any component using CSS props
Use CSS props to style your component. The props will be set with the values defined (and included in the page, at the root of your theamable DOM elements) by your theme-provider:
const Button = ({ children }) => { const style: CSSProperties = { backgroundColor: 'var(--primary-color-background)', color: 'var(--primary-color-text)', padding: 'var(--button-padding-medium)', fontWeight: 'var(--button-font-weight)', }; return <button style={style}>{children}</button>; };
import { MyTheme } from '@my-org.my-scope/my-theme';
import { Button } from '@my-org.my-scope/button';
() => (
<MyTheme.ThemeProvider>
<Button>I'm a themed button!</Button>
</MyTheme.ThemeProvider>
)
Create a new component to serve as the darker theme for your apps' 'dark mode':
Create an object with new design token values. Use the previously generated MyThemeScheme
type to ensure a proper use of design tokens.
/** @filename: my-dark-theme.ts */ import type { MyThemeSchema } from '@my-org.my-scope/my-theme'; export const darkThemeOverrides: Partial<MyThemeSchema> = { primaryColorBackground: '#151d33', primaryColorText: '#c9cdd6', };
Make this object available to other components by exporting it from its index.ts
file:
/** @filename: index.ts */ export { darkThemeOverrides } from './dark-theme';
Pass the overrides object to your default theme component to override or extend its design token values:
import { MyTheme } from '@my-org.my-scope/my-theme';
import { darkThemeOverrides } from '@my-org.my-scope/my-dark-theme';
import { Button } from '@my-org.my-scope/button';
() => (
<MyTheme.ThemeProvider overrides={darkThemeOverrides}>
<Button>I'm a themed button!</Button>
</MyTheme.ThemeProvider>
)