IBM Developer

Tutorial

Dynamic theming in React using IBM Carbon

Implement dynamic theming in React applications using IBM Carbon React Library, including system-based and custom theme switching

By Nimmy Povathody, Sowmya S

In today’s UI landscape, theming is essential for ensuring that applications align seamlessly with brand aesthetics and user preferences. With modern browsers and operating systems providing built-in support for light and dark modes, it is essential for UI teams to ensure their applications can adapt accordingly.

This tutorial explores theming with IBM Carbon Design System, a powerful tool designed to streamline theming for React applications. Learn how to use Carbon’s theming capabilities to meet diverse application requirements.

IBM Carbon Design System

Carbon is a IBM open-source design system that offers a comprehensive foundation for creating consistent, user-friendly digital experiences. Built on the IBM Design Language, Carbon provides:

  • Usable code: Ready-made React components and utilities for rapid development.
  • Design tools and resources: Assets, templates, and guidelines to maintain design consistency.
  • Human interface guidelines: Clear principles for user experience optimization.
  • Active community: A network of contributors for collaboration and support.

For more details, refer to the IBM Carbon Design System.

Theming for React frontend applications using IBM Carbon Design System

Now that we understand the importance of theming, let’s set up a theme using the Carbon Design System.

There are a few terminologies related to the library that we need to understand before proceeding:

  • Theme: The aesthetic you want to apply to your application.
  • Token: The series of color tokens that enable the aesthetic for UI elements.
  • Role: The schematic way in which tokens should be applied.
  • Value: The actual hex code assigned to the token.

For more inforation, refer to IBM Carbon themeing basics.

Integrate theming into your React application using @carbon/react

Note: @carbon/react is available only in v11 of Carbon package.

Prerequisites

  • This tutorial assumes you have a React project set up and are familiar with React front-end development. We will use the React boilerplate, create-react-app, with a few tweaks covered in the steps below.

  • For demonstration purposes, we are using macOS and Visual Studio Code as the IDE, but the principles apply to any React application.

Setting up boilerplate for Theming

  1. Create a React Project. Refer to Create React App for detailed instructions.

       npx create-react-app carbon-theming-demo
       cd carbon-theming-demo
    
  2. Install Carbon Libraries.

       npm install @carbon/react
    
  3. Remove or rename existing .css files to .scss. If you want to preserve existing styles, carefully integrate Carbon’s SCSS styles. We’ll demonstrate by creating a new SCSS file:

     @use '@carbon/react/scss/themes' as *;
     @use '@carbon/styles';
    

Theming approaches

With the above setup, there are different ways in which each application can implement theming:

  • Default OS/browser preference: The application should behave according to accessibility requirements when using the default OS/browser preference.
  • Controlled theme switching: Theme switching should be under the control of the application and not based on OS/browser settings.
  • Automatic theme token application: Components should automatically pick up theme tokens when using the Carbon Design System.
  • Custom theme token usage: Customize the theme token usage within components based on the theme switcher.

This tutorial covers how to implement each of these approaches in your application using the IBM Carbon React package.

Using system preferences for theme switching

In many cases, you’ll want your application to adapt to the user’s system-defined light or dark mode preference as the default theming behavior. Carbon makes this easy. Add the following code to your entry point SCSS file:

:root {
  @include themes.theme($white); /*Set default to white theme*/}
@media (prefers-color-scheme: dark) {
  :root {
    @include themes.theme($g100); /*Use dark theme for dark system preference*/}}

This code ensures your application starts in Carbon’s white theme and switches to the dark theme ($g100) if the user’s system prefers dark mode. On macOS, you can change your preferred theme in System Settings -> Appearance. You can also update your browser-specific theme, for example, in Chrome, go to Settings -> Appearance -> Mode and change it to Dark.

After implementing the above code, launch your application to see the theming in effect.

Carbon theming in detail

Carbon offers four base themes:

  • White
  • Gray 10
  • Gray 90
  • Gray 100

These themes use appropriate color tokens to support various color contrasts as per accessibility requirements. Additionally, custom theming can be implemented using the Carbon Design System . For more details, visit the IBM Carbon Design System.

Leveraging Carbon React components

Carbon’s React components automatically adapt to the active theme based on your system preferences or custom theming logic. Let’s see this in action:

  • Explore Carbon React storybook: The Carbon Design System offers a variety of pre-designed components to simplify frontend development. Browse the Carbon React Storybook to find examples of component usage and incorporate them into your application.

  • Import and use components: In the following source code example, we are importing form and its related components from @carbon/react into the entry point file, App.js, with the necessary attributes.

      import { FormGroup, Stack, TextInput, RadioButtonGroup, RadioButton, Button } from '@carbon/react';
    
      function App() {
      return (
      <>
      <header>
      <title>Carbon Theming</title>
      </header>
      <body className="App-header">
      <FormGroup className="form" legendText="Personal Details">
      <Stack gap={7}>
      <TextInput id="fn" labelText="First Name" />
      <TextInput id="ln" labelText="Last Name" />
      <RadioButtonGroup
      legendText="Gender"
      name="gender-radio"
      defaultSelected="g1"
      >
      <RadioButton labelText="Male" value="M" id="g1" />
      <RadioButton labelText="Female" value="F" id="g2" />
      <RadioButton labelText="Other" value="O" id="g3" />
      <RadioButton labelText="Doesn't Want to Mention" value="N" id="r4" />
      </RadioButtonGroup>
      <Button>Submit</Button>
      </Stack>
      </FormGroup>
      </body>
      </>);}
    
      export default App;
    
  • Run your application: Run your application using the following command to see the theme behavior based on system settings:

      `npm run start`
    

    Here, we are using macOS and have updated the system preference to dark theme. The following behavior can be observed:

    Theming with default system preference

Add custom theme toggling option to your application

To add custom theme toggling to your application, follow these steps to design a component that allows you to switch between themes using either a dropdown menu or a radio button.

Step 1. Create the theme selector component

We will use the Carbon dropdown component. Add a file ThemeSelector.js with the following code to implement the dropdown with React state management.

Note: Exit your application if it is running before updating the code.

import { Dropdown } from '@carbon/react';
import { useState } from 'react';
import PropTypes from 'prop-types';

const availableThemes = [
  { label: 'White', value: 'white' },
  { label: 'G10', value: 'g10' },
  { label: 'G90', value: 'g90' },
  { label: 'G100', value: 'g100' },
];

const ThemeSelector = ({ handleSelectionChange }) => {
  const [selectedTheme, setSelectedTheme] = useState(availableThemes[0]);
  const handleThemeChange = ({ selectedItem }) => {
    setSelectedTheme(selectedItem);
    handleSelectionChange(selectedItem.value);
  };
  return (
    <Dropdown
      id="theme-dropdown"
      label="Theme Switcher"
      titleText="Theme Switcher"
      selectedItem={selectedTheme}
      items={availableThemes}
      onChange={handleThemeChange}
      itemToString={(item) => (item ? item.label : '')}
      style={{ width: '385px', marginBottom: '30px'}} 
    />
  );
};
ThemeSelector.propTypes = {
  handleSelectionChange: PropTypes.func.isRequired,
};

export default ThemeSelector;

Step 2. Add CSS attributes for theme switching

Add the following CSS attributes to your style file to enable theme switching:

[data-carbon-theme='g10'] {
 @include themes.theme($g10);
}
[data-carbon-theme='g90'] {
@include themes.theme($g90);
}

[data-carbon-theme='g100'] {
@include themes.theme($g100);
}

Step 3: Update higher order component (HOC)

Update your App.js to manage state changes and apply the theming:

For the complete source code of the component, visit the Github repository.

Step 4: Launch your application

Run your application using:

`npm run start`

Observe how you can toggle the theme using the designed dropdown.

Developing themed custom components using carbon tokens

Instead of using pre-styled Carbon components, you can integrate theme style switching into custom components. Carbon provides color tokens with specific names that, when applied, ensure the desired color styling respects the active theme of the application.

Example: Themed button and modal

Here, we demonstrate using a button that opens a modal window. We apply Carbon tokens to replicate the behavior:

@use '@carbon/styles';
@use '@carbon/react/scss/theme' as theme;

.customComponent {
  button {
    /* Base styles */
    color: theme.$text-inverse;
    background-color: theme.$icon-secondary;

Explanation

The usage of tokens for the button color ensures it respects the theme used in the application. The SCSS code above applies the appropriate theme-based color styling to the button within the custom component.

Custom component when theme tokens are applied

Conclusion

This tutorial guided you through implementing theming in React applications using IBM’s Carbon React Library. It covered essential concepts such as themes, tokens, and roles, and explained how to integrate system-based and custom theme switching. By using Carbon’s pre-designed components and tokens, you can create a dynamic and accessible user interface. The tutorial also provided practical examples, including a custom theme toggling component and themed custom components.