Theming in React

Debbie O'Brien - Mar 10 '22 - - Dev Community

Theming is a fascinating topic and a really important one these days as more and more people add light and dark mode to their sites and companies change the theme of their site or part of their site on specific dates to celebrate occasions such as christmas, pride week etc.

But where do we start when it comes to creating themes? It all starts with the designers. They are the ones who are creating the themes. Each theme should have a list of design tokens that show the theme colors, paddings, margins, fonts, etc. These tokens can be exported from tools such as Figma and then used in a theme component.

In this example I will show you how to do theming in React using Bit, however if you are not using Bit this will still work in any React app and you can install the one Bit component that we are using though npm or yarn. The Theme Provider component from teambit will convert these design tokens from JSON format to usable CSS variables without you having to do any extra work, which is kinda cool.

By using Bit we are making sure our components are fully independent and can be easily installed into any app. If you are not using Bit then you will need to change the import statements to use relative paths to your components. And if you are not using typescript then feel free to change the file extension to .jsx and ignore the schema which is just for type checking.

So lets get started with theming in React.

Step 1: Create your Theme Provider Component

  1. Create a new theme provider component.

  2. Add a theme-schema.tsx file and include all types for your design tokens.

export type ThemeSchema = {
  myColorText?: string
  myFontSize?: string
  myBorderColor?: string
  myBorderRadius?: string
};
Enter fullscreen mode Exit fullscreen mode

Add a '?' to make the tokens optional so you can use tokens from the default theme as well as override any tokens the theme wants to change.

  1. Add a default-theme-tokens.tsx file which should include all design tokens and values for your default theme.
import { ThemeSchema } from './theme-schema';

export const defaultTheme: ThemeSchema = {
  myColorBackground: '#ffffff',
  myColorText: 'purple',
  myFontSize: '26px',
  myBorderColor: 'purple',
  myBorderRadius: '5px',
};
Enter fullscreen mode Exit fullscreen mode
  1. Install the ThemeProvider component from teambit.
bit install @teambit/base-react.theme.theme-provider
// or
npm install @teambit/base-react.theme.theme-provider
Enter fullscreen mode Exit fullscreen mode
  1. Import the createTheme function from teambit's Theme Provider component and the defaultTheme from the default-theme-tokens file in your theme-provider.tsx file. Create your theme using the createTheme() function passing into it the defaultTheme as the value for theme.
import { createTheme } from '@teambit/base-react.theme.theme-provider'
import { defaultTheme } from './default-theme-tokens'

export const Theme = createTheme({
  theme: defaultTheme
})
Enter fullscreen mode Exit fullscreen mode

You supply the design tokens directly to the createTheme function and it does the rest for you to convert the tokens to usable css (both in modules and directly in your css).

  1. Add compositions, tests and docs.

Step 2: Use your Theme Provider

  1. Import the Theme from the ThemeProvider component you created.
import { Theme } from '@learn-bit-react/theming.themes.theme-provider'
Enter fullscreen mode Exit fullscreen mode
  1. Wrap all components in the theme provider to see the theme applied to your components.
import React from 'react'
import { Theme } from '@learn-bit-react/theming.themes.theme-provider'
import { Button } from '@learn-bit-react/theming.example.button'

export const MyApp = () => {
  return (
    <Theme.ThemeProvider>
      <Button>Hello</Button>
    </Theme.ThemeProvider>
  )
}
Enter fullscreen mode Exit fullscreen mode

Button using Default Theme

You can install and use the Button component from this demo as an example or create your own and add some styles to it using css variables.

Step 3: Create a Dark Theme Component

  1. Create a new theme component.
bit create react themes/dark-theme
Enter fullscreen mode Exit fullscreen mode
  1. Add a dark-theme-tokens.tsx file with the design tokens and values you want to override from the default theme.
import { ThemeSchema } from '@learn-bit-react/theming.themes.theme-provider'

export const darkTheme: ThemeSchema = {
  myColorBackground: '#000',
  myColorText: 'red',
  myBorderColor: 'red'
}
Enter fullscreen mode Exit fullscreen mode

Import the ThemeSchema for type checking.

  1. Import the Theme from the the theme provider component you just created as well as the darkTheme from the dark-theme-tokens file.
import React from 'react';
import { Theme } from '@learn-bit-react/theming.themes.theme-provider';
import { darkTheme } from './dark-theme-tokens';

export const DarkTheme = ({ children }) => {
  return (
    <Theme.ThemeProvider overrides={darkTheme}>
      {children}
    </Theme.ThemeProvider>
  );
};
Enter fullscreen mode Exit fullscreen mode

Add the darkTheme to the overrides prop of the theme provider.

  1. Make sure your index file is exporting both the DarkTheme component as well as the darkTheme tokens.
export { DarkTheme } from './dark-theme';
export { darkTheme } from './dark-theme-tokens';
Enter fullscreen mode Exit fullscreen mode
  1. Add compositions, tests and docs.

Step 4: Use your Theme in a Component

  1. Import the Theme from the ThemeProvider component you created as well as the DarkTheme and any components you want to render.
import React from 'react'
import { Theme } from '@learn-bit-react/theming.themes.theme-provider'
import { DarkTheme } from '@learn-bit-react/theming.themes.dark-theme'
import { Button } from '@learn-bit-react/theming.example.button'
Enter fullscreen mode Exit fullscreen mode

Wrap all components in the Theme Provider component and use the overrides prop to change the theme to darkTheme.

export const MyApp = () => {
  return (
    <Theme.ThemeProvider overrides={darkTheme}>
      <Button>Hello</Button>
    </Theme.ThemeProvider>
  )
}
Enter fullscreen mode Exit fullscreen mode

Button with Dark Theme applied

Use theme like a wrapper component You can alternatively use the component like this which will work exactly the same as the example above.

export const MyApp = () => {
  return (
    <DarkTheme>
      <Button>Dark Theme</Button>
    </DarkTheme>
  )
}
Enter fullscreen mode Exit fullscreen mode

Multiple Themes

You can also use the default theme and have a part of your app be wrapped in a different theme.

export const MyApp = () => {
  return (
    <Theme.ThemeProvider>
      <Button>Default Theme</Button>
      {/* A dark themed button inside a default theme */}
      <DarkTheme>
        <Button>Dark Theme</Button>
      </DarkTheme>
    </Theme.ThemeProvider>
  )
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

And thats how you do theming in React. For more info on how the components work or to learn more on theming and React context check out:

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .