Search code examples
javascriptreactjscustomizationantd

How to customize antd theme on runtime?


I have been working with antd for quite sometime now. So far in my react app I have customized antd theme in webpack configuration and have updated default less variables.

Or If Im using create react app, in that case I customized the theme by modifyling variables in config-overrides.js.

But Now I have a feature in my app to have multiple themes and the user could choose the theme of the application on runtime i-e on clicking a button I want to change the theme of the entire application. How is this possible with antd since in its case all the customization is done in the build configuration.

Any help would be appreciated.

Here's the documentation link I have gone through. But it doesn't provide anything for my usecase.


Solution

  • $ npm install --save antd-theme
    

    app.jsx

    import { Button, Select } from 'antd';
    import { ThemeProvider, useTheme } from 'antd-theme';
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { SketchPicker } from 'react-color';
    
    const initialTheme = {
      name: 'default',
      variables: { 'primary-color': '#00ff00' },
    };
    
    const ThemeSelect = () => {
      const [{ name, variables, themes }, setTheme] = useTheme();
    
      return (
        <>
          <Select
            style={{ width: 100 }}
            value={name}
            onChange={
              (theme) => setTheme({ name: theme, variables })
            }
          >
            {
              themes.map(
                ({ name }) => (
                  <Select.Option key={name} value={name}>
                    {name}
                  </Select.Option>
                )
              )
            }
          </Select>
          <SketchPicker
            color={variables['primary-color']}
            onChange={(value) => {
              // Will update all css attributes affected by primary-color
              setTheme({ name, variables: { 'primary-color': value.hex } });
            }}
          />
        </>
      );
    };
    
    const App = () => {
      const [theme, setTheme] = React.useState(initialTheme);
      return (
        <ThemeProvider
          theme={theme}
          onChange={(value) => setTheme(value)}
        >
          <ThemeSelect />
          <Button type="primary">Button</Button>
        </ThemeProvider>
      );
    };
    
    ReactDOM.render(<App />, document.getElementById('root'));
    

    config-overrides.js

    const { override, fixBabelImports, addLessLoader, addPostcssPlugins, adjustStyleLoaders, addWebpackPlugin } = require('customize-cra');
    
    const AntdThemePlugin = require('antd-theme/plugin');
    
    module.exports = override(
      fixBabelImports('import', {
        libraryName: 'antd',
        libraryDirectory: 'es',
        style: true,
      }),
      addLessLoader({
        javascriptEnabled: true,
      }),
      adjustStyleLoaders(
        (loaders) => {
          loaders.use[0] = {
            loader: AntdThemePlugin.loader
          }
        }
      ),
      addWebpackPlugin(
        new AntdThemePlugin({
          variables: ['primary-color'],
          themes: [
            {
              name: 'dark',
              filename: require.resolve('antd/lib/style/themes/dark.less'),
            },
            {
              name: 'compact',
              filename: require.resolve('antd/lib/style/themes/compact.less'),
            },
          ],
        })
      ),
    );