reactjsantddarkmode

How do I make my web site respect user's dark mode settings with Antd?


I understand how to change my web site theme programmatically or using states with Antd and react, but how do I respect user settings for dark mode, without having to reload the web site for the theme to apply, when browser changes mode automatically based on system settings.

My understanding is that since Antd 5.x moved to cssinjs, I can no longer use theme colors in my css anymore, so @media-query isn't an option, but I might be wrong.


Solution

  • Like what one of the commenters mentioned, add a listener to listen on changes in the system's color scheme. If it changes, then change the darkMode state so React can re-evaluate and propagate it to the ConfigProvider.

    Be sure to also include another useEffect to do the initial evaluation for setting darkMode on initial page load.

    Here's a minimum viable example for implementing it:

    import React, { useEffect, useState, useCallback } from "react";
    import { Button, ConfigProvider, Input, Space, theme } from "antd";
    
    const App: React.FC = () => {
      const [darkMode, setDarkMode] = useState(false);
      const windowQuery = window.matchMedia("(prefers-color-scheme:dark)");
    
      const darkModeChange = useCallback((event: MediaQueryListEvent) => {
        console.log(event.matches ? true : false);
        setDarkMode(event.matches ? true : false);
      }, []);
    
      useEffect(() => {
        windowQuery.addEventListener("change", darkModeChange);
        return () => {
          windowQuery.removeEventListener("change", darkModeChange);
        };
      }, [windowQuery, darkModeChange]);
    
      useEffect(() => {
        console.log(windowQuery.matches ? true : false);
        setDarkMode(windowQuery.matches ? true : false);
      }, []);
    
      return (
        <ConfigProvider
          theme={{
            algorithm: darkMode ? theme.darkAlgorithm : theme.compactAlgorithm
          }}
        >
          <Space>
            <Input placeholder="Please Input" />
            <Button type="primary">Submit</Button>
          </Space>
        </ConfigProvider>
      );
    };
    
    export default App;
    

    DEMO