Telerik blogs
KendoReactT2_1200x303

Once you have a dark theme, how do you implement a toggle between dark and light mode? What if you’d like to make dynamic changes to the themes in the run-time?

As developers, we love to be able to switch our favorite sites from light to dark mode. My teammate Kathryn wrote a helpful blog explaining how you can create a dark theme with KendoReact, which left an interesting question on the table. The question, which made me very curious, is this: Once you have a dark theme, how do you implement the toggle between dark and light mode?

Is this something you’ve wondered about? You are in the right place.

The Challenge

Kathryn’s blog explains in detail the different methods of creating beautiful dark theme with KendoReact. Whichever of the methods you choose, at the end, you will have two stylesheets containing the styles for the light and dark themes.

You might upload these two stylesheets on a content delivery network (CDN) and toggle between the links with the help of a simple ThemeChooser dropdown component. I’ve made a simple example to demonstrate this approach by using our pre-built Kendo UI Default light and dark themes:

What if you’d like to make dynamic changes to the themes in the run-time? You will probably need to upload a new version of the stylesheets with every change. This can become an overkill if you want to change a single color. Let’s find out how to resolve this!

The Solution

There are two steps for implementing dynamic switching:

  1. Compile Sass stylesheets into CSS at run-time
  2. Implement a provider for toggling those styles

In the application, I used Gulp task runner to compile the Sass files to CSS and then append these to the public folder so they can be available for the client. Then, I used the react-css-theme-switch npm package to swap between pre-fetched SASS-compiled stylesheets at run-time.

If you’d like to follow the steps as we go, you can find the full code in this GitHub repository. Now, let’s dive into the application setup!

Project Setup

We are going to use Create React App to quickly scaffold a new React project. Run the command below in your terminal to create a new React project.

$ npx create-react-app kendo-react-dark-mode
$ cd kendo-react-dark-mode

This project requires:

  • Node.js v14 or newer
  • Gulp v4
  • npm v7 or newer (if using npm version < 7, make sure that the following dependencies are installed: postcss postcss-calc autoprefixer)
  • KendoReact – free 30-day trial available

After the project creation is complete, run the following commands to get into the project directory and install all dependencies.

$ npm install

Finally, you can start the development server by running the $ npm start command.

Installing the KendoReact Components

For this demo, we are going to add the React Button and React Switch components from the KendoReact library, so we start with the installation of the npm packages and dependencies.

$ npm install --save @progress/kendo-react-buttons @progress/kendo-react-inputs @progress/kendo-react-intl @progress/kendo-drawing @progress/kendo-licensing

Note: KendoReact is a commercial UI component library, and as a part of this you will need to provide a license key when you use the components in your React projects. You can get a license key through a free trial or by owning a commercial license. For more information, you can head over to the KendoReact Licensing page.

Adding the Stylesheets for Light and Dark Themes

First, we will install the KendoReact Default Theme via npm:

$ npm install --save @progress/kendo-theme-default

Then, we need to create the Sass stylesheets that will contain the KendoReact styles. To achieve this, we just have to import the SCSS variables that we need for each theme. For example, for the light theme we will use the default styling without further customizations:

// sass/light-theme.scss
@import "~@progress/kendo-theme-default/dist/all.scss";

And for the dark theme:

// sass/dark-theme.scss
$dark-theme: true;
$border-radius: 2px;
$primary: #42e142;
$secondary: #f6f6f6;
$info: #3e80ed;
$success: #5ec232;
$warning: #fdce3e;
$error: #d51923;
$body-text: #ffffff;
$body-bg: #000000;
$headings-text: #ffffff;
$subtle-text: #e0e0e0;
$disabled-text: #d0d0d0;
$component-text: #ffffff;
$component-bg: #101010;
$base-text: #ffffff;
$base-bg: #151515;
$hovered-text: #ffffff;
$hovered-bg: #202020;
$selected-text: #ffffff;
$selected-bg: #42e142;
$kendo-button-text: #ffffff;
$kendo-button-bg: #404040;
$link-text: #42e142;
$link-hover-text: #38c138;
$series-a: #ff6358;
$series-b: #ffe162;
$series-c: #4cd180;
$series-d: #4b5ffa;
$series-e: #ac58ff;
$series-f: #ff5892;
$kendo-switch-on-thumb-bg: #42e142;
$kendo-switch-off-thumb-bg: #42e142;
@import ~@progress/kendo-theme-default/dist/all.scss;

Compiling the SASS Files with Gulp

In this step, we will create a Gulp task that will compile Sass files to CSS and then append these to the public folder of our application so they can be available for the client to be pre-fetched and injected.

Install Gulp and necessary dependencies to minify and resolve imports:

$ npm install –save-dev gulp @progress/kendo-theme-tasks node-sass

And create a gulpfile.js:

const { kendoSassBuild } = require('@progress/kendo-theme-tasks/src/build/kendo-build');
const nodeSass = require('node-sass');
const { series } = require("gulp");

const themes = ['light', 'dark'];

function buildStyles(cb) {
  themes.forEach((theme) => {
    kendoSassBuild({
      file: `./src/sass/${theme}-theme.scss`,
      output: {
        path: './public'
      },
      sassOptions: {
        implementation: nodeSass,
        outputStyle: 'compressed'
      }
    });
    cb();
  });
}
exports.sass = series(buildStyles);

Interesting fact: There is a new, simplified way of compiling Kendo UI themes with all required plugins (postcss, postcss-calc and autoprefixer) and configured package importer that resolves the themes specific import paths.

For more information, you can check out this effort in the kendo-theme-tasks repo: https://github.com/telerik/kendo-theme-tasks#building-from-scss


Automatically Compile the Sass Files

In the “scripts” property of your package.json file, add “prestart” command. It will run before start as the name suggests.

"scripts": {
  "prestart": "gulp sass",
  ...
},

Toggling Between the Themes

Now, we have our compiled CSS themes inside the public folder. We can proceed to use them in our application.

In the demo, I used the react-css-theme-switch npm package to switch between the themes. Add it to your project via:

$ npm install --save react-css-theme-switcher

Then, in index.js file, we will add the ThemeSwitcherProvider as a wrapper for our App component. This provider will store our themes and current theme.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { ThemeSwitcherProvider } from "react-css-theme-switcher";

const themes = {
  dark: `${process.env.PUBLIC_URL}/dark-theme.css`,
  light: `${process.env.PUBLIC_URL}/light-theme.css`,
};

ReactDOM.render(
  <React.StrictMode>
    <ThemeSwitcherProvider
      themeMap={themes}
      defaultTheme="light"
      insertionPoint="styles-insertion-point"
    >
      <App />
    </ThemeSwitcherProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

In the App.js file, we will also use the useThemeSwitcher hook, which will change themes and fetch other metadata:

import React from "react";
import "./App.css";
import { useThemeSwitcher } from "react-css-theme-switcher";
import { Button } from "@progress/kendo-react-buttons";
import { Switch } from "@progress/kendo-react-inputs";

function App() {
  const [isDarkMode, setIsDarkMode] = React.useState(true);
  const { switcher, currentTheme, status, themes } = useThemeSwitcher();

  const toggleTheme = () => {
    setIsDarkMode(!isDarkMode);
    switcher({ theme: isDarkMode ? themes.dark : themes.light });
  };

  // Avoid theme change flicker
  if (status === "loading") {
    return null;
  }

  return (
    <div className="main fade-in k-body">
      <h1>The current theme is: {currentTheme}</h1>
      <Switch checked={isDarkMode} onChange={toggleTheme} />
      <Button style={{ width: 300, marginTop: 30 }} themeColor="primary">
        Primary Button
      </Button>
    </div>
  );
}

export default App;

And voila! We have implemented a dynamic dark mode switch via a theme provider in a React application.

Your Feedback Matters

You might be used to skipping such asks, but the truth is that your feedback really matters. I’d appreciate it if you leave a comment below.


Silviya Boteva
About the Author

Silviya Boteva

Silviya Boteva is a frontend developer at Progress. Her passion is creating a pixel-perfect UI and breathing life into the UI components with React. In her heart, she is a traveler, a Bulgarian folklore dancer, bookaholic and coffee addict. Her most loved ones (except her family members) are her two sweet cats.

Related Posts