Dark mode in React: An in-depth guide - LogRocket Blog (2024)

Editor’s note: This guide to dark mode in React was last updated on 29 March 2023 to reflect changes to React and provide more information about dark mode and a new section on testing for dark mode. Check out our new UX blog to learn more about bettering your UX.

Dark mode in React: An in-depth guide - LogRocket Blog (1)

As we move towards a better and more accessible UX on the web, dark mode has become a mainstream feature for web apps. Developing dark mode is more than just adding a simple toggle button and managing the CSS variable. Here we will discuss dark mode and create a complete dark mode experience in a React app. You can find the demo application and its code on GitHub.

Jump ahead:

  • What is dark mode?
  • Accessibility in dark mode
  • Why should you use dark mode?
  • Using system settings
  • Managing themes using CSS variables
  • Implementing a color scheme toggle
  • Emulating dark mode in browsers
  • Storing the user’s preferred mode using use-persisted-state
  • Selecting dark theme colors
  • Handling images in dark mode
  • Should you write tests for dark mode?

What is dark mode?

Dark mode is a UI feature that changes the color scheme of an application or website to use darker colors, typically replacing white or bright backgrounds with black or dark gray backgrounds. This creates a high-contrast visual effect that makes reading text and viewing content easier in low-light or dark environments, reducing eye strain and improving overall readability.

Dark mode has gained popularity for its functional benefits, including enhanced accessibility for users with visual impairments, improved focus and productivity in professional settings, and its sleek and modern aesthetic appeal.

Accessibility in dark mode

Dark mode has gained popularity not only for its aesthetic appeal but also for its potential benefits in terms of accessibility. Some key considerations for accessibility in dark mode include:

  • Reduced eye strain: Dark mode can reduce eye strain and fatigue, particularly in low-light conditions, as it reduces the amount of blue light emitted by screens, which can contribute to eye strain
  • Improved readability: The high contrast between dark backgrounds and light text can enhance readability, particularly for users with visual impairments or conditions such as dyslexia
  • Reduced glare: Dark mode can help reduce screen glare, which can be particularly beneficial for users with sensitivity to bright lights or who are prone to migraines
  • Customizability: Dark mode often allows for the customization of color schemes, contrast levels, and font sizes, making it easier for users with visual impairments to tailor the interface to their specific needs
  • Accessibility standards: Many accessibility standards, such as the Web Content Accessibility Guidelines (WCAG), recommend using high-contrast color schemes, which dark mode can help achieve

Why should you use dark mode?

Dark mode offers several advantages that can enhance the UX. First, dark mode can reduce the strain on your eyes, particularly when using screens for extended periods by reducing the amount of blue light emitted and creating a softer, more comfortable visual experience.

Dark mode can also help conserve battery life on devices with OLED or AMOLED screens, as these screens use less power to display darker pixels compared to brighter ones. In addition, dark mode can help improve focus and productivity. Dark mode can create a focused environment by minimizing distractions and reducing visual clutter, enhancing productivity, particularly in low-light or nighttime settings.

Dark mode has become popular for its sleek and modern appearance, and many users find it visually appealing and enjoyable to use. Lastly, dark mode often comes with customization options, allowing users to choose from different color schemes, contrast levels, and font sizes, making it a versatile option tailored to individual preferences.

Using system settings

No one wants to hurt a user’s eyes when they land on their website! It’s best practice to set the app’s theme according to the device’s settings. CSS media queries, generally known for usage with responsive design, also help us check for other device characteristics.

Here, we will use the prefers-color-scheme that gives us dark, light, or no-preference based on the device’s selected color scheme. And, like any other media query, styles in this block will be applied when the device’s color scheme is set to dark. Placing it in some component styles will look like this:

body { background-color: #dadada; color: #1f2023;}@media (prefers-color-scheme: dark) { body { background-color: #1f2023; color: #dadada; }}

This is a good start, but one cannot keep adding these styles in each component. In this case, CSS variables are the answer.

Managing themes using CSS variables

CSS variables are one tool that was missing from web styling for a long, long time. Now that they are available with all browsers, CSS is more fun and less of a pain. CSS variables are scoped to the element(s) on which they are declared and participate in the cascade (for example, elements are override values for children). We can use CSS variables to define themes of our application. Here’s a small snippet to recall how CSS variables are declared:

body { --color-background: #fafafa; --color-foreground: #1f2023;}

To use these variables in our components, we will swap color codes with variables:

.App-header { background-color: var(--color-background); color: var(--color-foreground);}

Now that our colors are defined via CSS variable, we can change values on top of our HTML tree (<body>), and the reflection can be seen on all elements:

body { --color-background: #fafafa; --color-foreground: #1f2023;}@media (prefers-color-scheme: dark) { body { --color-background: #1f2023; --color-foreground: #efefef; }}

Implementing a color scheme toggle

At this point, we have the simplest solution based on device preferences. Now, we have to scale it for devices that do not natively support dark mode. In this case, we have to make it easy for users to set their preferences for our web app. I opted for react-toggle to make our solution better at a11y, along with pleasing aesthetics. This can be achieved via a simple button and useState. Here’s what our toggle will look like:

Dark mode in React: An in-depth guide - LogRocket Blog (2)

Here is how our toggle component looks:

import React, { useState } from "react";import Toggle from "react-toggle";export const DarkModeToggle = () => { const [isDark, setIsDark] = useState(true); return ( <Toggle checked={isDark} onChange={({ target }) => setIsDark(target.checked)} icons={{ checked: "🌙", unchecked: "🔆" }} aria-label="Dark mode toggle" /> );};

This component will hold the user’s selected mode, but what about the default value? Our CSS solution respected the device’s preference. To pull media query results in our React component, we will use react-responsive. Under the hood, it uses Window.matchMedia and re-renders our component when the query’s output changes.

An updated version of the button looks like the following:

import React, { useState } from "react";import Toggle from "react-toggle";import { useMediaQuery } from "react-responsive";export const DarkModeToggle = () => { const [isDark, setIsDark] = useState(true); const systemPrefersDark = useMediaQuery( { query: "(prefers-color-scheme: dark)", }, undefined, (isSystemDark) => setIsDark(isSystemDark) ); return ( <Toggle checked={isDark} onChange={({ target }) => setIsDark(target.checked)} icons={{ checked: "🌙", unchecked: "🔆" }} aria-label="Dark mode toggle" /> );};

The useMediaQuery Hook takes a query, initial value, and an onChange handler that is fired whenever the query’s output is changed.

Emulating dark mode in browsers

Now, our component will be in sync with the device’s preferences, and its value will be updated accordingly. But, how can we test if it’s done right? Thanks to developer-friendly browsers, we can emulate device preferences from browser inspectors; here is how it looks in Firefox:

Dark mode in React: An in-depth guide - LogRocket Blog (3)

It’s time to connect our toggle component’s state change to CSS. This can be done with several different techniques. Here, we have opted for the simplest one: adding a class on the body tag and letting CSS variables do the rest. To accommodate this, we will update the CSS of our body tag:

body { --color-background: #fafafa; --color-foreground: #1f2023;}body.dark { --color-background: #1f2023; --color-foreground: #efefef;}

We will also update our DarkModeToggle component with this useEffect Hook to add and remove classes to the body tag based on the isDark state:

...useEffect(() => { if (isDark) { document.body.classList.add('dark'); } else { document.body.classList.remove('dark'); }}, [isDark]); ...

Storing the user’s preferred mode using use-persisted-state

If we keep the user’s preferred color scheme in the component’s state, it might become problematic because we won’t be able to get the values outside of this component. Also, it will vanish as soon as our app is mounted again. Both problems can be solved in different ways, including with React Context or any other state management approach.

One other solution is to use the use-persisted-state. This will help us fulfill all requirements. It persists the state with localStorage and keeps the state in sync when the app is open in different browser tabs. We can now move our dark mode state in a custom Hook that encapsulates all logic related to media query and persistent state. Here is how this Hook should look:

import { useEffect, useMemo } from "react";import { useMediaQuery } from "react-responsive";import createPersistedState from "use-persisted-state";const useColorSchemeState = createPersistedState("colorScheme");export function useColorScheme() { const systemPrefersDark = useMediaQuery( { query: "(prefers-color-scheme: dark)", }, undefined ); const [isDark, setIsDark] = useColorSchemeState(); const value = useMemo( () => (isDark === undefined ? !!systemPrefersDark : isDark), [isDark, systemPrefersDark] ); useEffect(() => { if (value) { document.body.classList.add("dark"); } else { document.body.classList.remove("dark"); } }, [value]); return { isDark: value, setIsDark, };}

The toggle button component will be much simpler now:

import React from "react";import Toggle from "react-toggle";import { useColorScheme } from "./useColorScheme";export const DarkModeToggle = () => { const { isDark, setIsDark } = useColorScheme(); return ( <Toggle checked={isDark} onChange={({ target }) => setIsDark(target.checked)} icons={{ checked: "🌙", unchecked: "🔆" }} aria-label="Dark mode toggle" /> );};

Selecting dark theme colors

While dark mode itself can be considered an accessibility feature, we should focus on keeping this feature accessible for a wider audience. We used react-toggle in our demo to ensure the button used for changing the color scheme follows all a11y standards. Another important part is the selection of background and foreground colors in both dark and light modes. In my opinion, colors.review is a great tool to test the contrast ratio between colors. Having an AAA grade makes our apps easier to navigate and more comfortable to look at. Here’s our app:

Dark mode in React: An in-depth guide - LogRocket Blog (4)

Handling images in dark mode

For better aesthetics, we usually have pages with bright images. In dark mode, bright images might become a discomfort for users. Several techniques can avoid these issues, including using different images for both modes and changing colors in SVG images. One way is to use CSS filters on all image elements; this will help lower eye strain when bright images appear on the user’s canvas. To enable this, we can add the following to our global styles:

body { --color-background: #fafafa; --color-foreground: #1f2023; --image-grayscale: 0; --image-opacity: 100%;}body.dark { --color-background: #1f2023; --color-foreground: #efefef; --image-grayscale: 50%; --image-opacity: 90%;}img,video { filter: grayscale(var(--image-grayscale)) opacity(var(--image-opacity));}

Should you write tests for dark mode?

Testing is an essential practice in software development to ensure the quality and reliability of applications. When implementing dark mode in a React app, you may wonder whether writing tests specifically for the dark mode feature is necessary. Here are some points to consider:

Complexity of dark mode implementation

If the dark mode feature in your React app is relatively simple, such as just changing the background color and text color, and doesn’t involve complex logic or interactions, you could argue that writing tests specifically for dark mode are not necessary. In such cases, you can rely on your regular testing practices, such as unit testing and end-to-end testing, to cover the dark mode behavior as part of the overall application testing.

Importance of dark mode in the app

Consider the significance of the dark mode feature in your React app. Suppose dark mode is a critical part of the UX, and its correct functioning is crucial for the overall usability and accessibility of the app. In that case, writing tests specifically for dark mode is advisable. Dark mode has become increasingly popular as a user preference, especially for applications used in low-light conditions, and ensuring its proper functioning can greatly enhance the UX.

Accessibility requirements

Dark mode can affect accessibility because it affects color contrast ratios, font sizes, and other visual elements. Suppose your app needs to meet accessibility standards, such as the Web Content Accessibility Guidelines (WCAG). In that case, it’s important to include testing for dark mode to ensure that it meets the required accessibility criteria. Writing tests for dark mode can help you catch any accessibility issues early in the development process and ensure that your app remains accessible to all users.

Development team’s testing practices

Consider the testing practices followed by your development team. If your team has a culture of writing thorough tests for all features and components, including dark mode, then it’s likely beneficial to write tests specifically for dark mode as well. Consistent testing practices across the team can help ensure higher quality and reliability in the application.

If you decide to write tests for your dark mode, consider some of these scenarios to ensure the correct functioning of your dark mode feature in your app:

  • Identify dark mode components: Identify the components or sections affected by dark mode, such as buttons, text, images, backgrounds, or other UI elements
  • Define test scenarios: Define the scenarios to be tested, including switching between dark and light modes, default mode based on user preferences, or device settings
  • Write test cases: Use testing libraries like Jest or React Testing Library to write unit or integration tests for your components. Test the expected behavior of components under different dark mode conditions
  • Test accessibility: Ensure dark mode meets accessibility standards by using accessibility tools like Axe to check for color contrast, font sizes, and other visual elements
  • Update test suites: Keep your test suites up-to-date as you modify or refactor your dark mode implementation

By following these steps, you can create a comprehensive test suite for your dark mode implementation, helping catch issues early and ensuring correct functioning and accessibility.

Conclusion

In conclusion, dark mode is a UI feature that offers potential benefits in terms of accessibility, reduced eye strain, extended battery life, improved focus and productivity, and customization options. Considering these advantages, dark mode can be a worthwhile option to enhance the UX in various applications and websites.

Over 200k developers use LogRocket to create better digital experiencesLearn more →

Accessibility in web apps today is not just a utility; it’s a basic requirement. Dark mode should be considered a full feature that requires attention, just like any other critical feature. In this article, we have established a way to implement dark mode to its full extent. Please let us know in the comments if you feel anything has been missed. Happy coding!

Get set up with LogRocket's modern React error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to getan app ID
  2. Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, notserver-side

    • npm
    • Script tag
    $ npm i --save logrocket // Code:import LogRocket from 'logrocket'; LogRocket.init('app/id'); 
    // Add to your HTML:<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script><script>window.LogRocket && window.LogRocket.init('app/id');</script> 
  3. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • NgRx middleware
    • Vuex plugin

Get started now

Dark mode in React: An in-depth guide - LogRocket Blog (2024)

FAQs

How to do dark mode in React? ›

To toggle between the light and dark modes in a React app, we need to add a switch button to it. Adding a switch can be done by importing the Switch Component from Material UI and then defining it in the App component.

What is React email? ›

The next generation of writing emails. High-quality, unstyled components for creating emails. Website · GitHub · Discord.

How to toggle button in React? ›

The onClick handler is a prop in React that is triggered when the user clicks on an element. In our toggle button component, we set the onClick handler of the button to the handleChange function. When the button is clicked, the onClick handler triggers the handleChange function, which toggles the state of the button.

How do I force dark mode? ›

For instance, on Windows 10, go to Settings > Personalization > Colors, and then choose "Dark" under "Choose Your Default App Mode." On macOS, you can simply navigate to System Preferences > General and activate the dark mode.

What is the React hook for dark mode? ›

With just a few lines of code, you can enable dark mode in your React application. By invoking this hook, you'll receive the current dark mode state and a function to toggle it. The “useDarkMode” hook dynamically updates the HTML body class to apply the “dark-mode” styling whenever dark mode is enabled.

Is React still being used? ›

The short answer is YES! As we can see from the benefits listed in this article, it is easy to see why React is still enjoying its popularity in 2022. It was voted the 2nd most popular web framework for developers, only falling behind Node.

Which React email editor is best? ›

GitHub - zalify/easy-email-editor: Easy Email Editor is a feature-rich, top open-source SaaS email editor based on React and MJML.

Is React owned by Google? ›

Some software engineers prefer not to call it a "framework" since it gives the developers much more freedom than Angular or Vue. Just like Angular is supported by Google, React. js is maintained by Facebook and a community of developers. Both are open source and free to use under the MIT license.

How do I enable or disable a button in React? ›

This is done by setting the button's disabled attribute to true. It's used for controlled interactions, like form submissions with valid data. A disabled button becomes unclickable and visually signifies to the user that its functionality is currently unavailable.

What is React material UI? ›

Material UI is an open-source React component library that implements Google's Material Design. It's comprehensive and can be used in production out of the box. Get started View templates. $ npm install @mui/material @emotion/react @emotion/styled. Search for React UI libraries.

How do I add a Dark theme? ›

Open your device's Settings app . Select Accessibility. Under "Color and motion," turn on Dark theme.

How do I make my studio Dark theme? ›

Studio features both a light theme and dark theme. If your operating system supports light and dark modes, the default option mirrors your system mode. To explicitly change themes, search for the Theme option and select either Default, Light, or Dark.

How do you make idle Dark theme? ›

In the "IDLE Preferences" window, go to the "Highlights" tab. 4. Under "Available Highlights," you'll find a list of pre-defined themes like "IDLE Classic" and "IDLE Dark." Select the one you prefer.

How do I turn on darkness mode? ›

Open your device's Settings app . Select Accessibility. Under "Color and motion," turn on Dark theme.

How to change Color theme in React? ›

Don't forget to use the context.
  1. import React from "react"; import ReactDOM from "react-dom/client"; import "./index.scss"; import App from "./App"; ...
  2. /* Dark Theme Colors */ $neutral-0: #FFFFFF; $neutral-500: #949497; ...
  3. @use 'colors' as *; html[data-theme="dark"] { --background-color: #{$neutral-900};
Oct 20, 2023

How to switch dark mode in js? ›

Steps to create Dark-Mode websites using HTML, CSS, and JavaScript:
  1. Create an HTML document.
  2. Add CSS properties to the body and add dark-mode class properties in CSS.
  3. Add buttons to switch between Dark and Light Mode.
  4. Add functionality to buttons to switch between dark-mode and light-mode using JavaScript.
May 10, 2024

How do you write code in dark mode? ›

Steps to Create Dark/Light Mode
  1. Create an HTML Document.
  2. Create CSS for the document file as well as for dark mode.
  3. Add a switch/toggler to toggle between light and dark modes.
  4. Add functionality to the switch/toggler to toggle between light and dark mode using JavaScript or jQuery code.
May 14, 2024

Top Articles
Latest Posts
Article information

Author: Trent Wehner

Last Updated:

Views: 5951

Rating: 4.6 / 5 (76 voted)

Reviews: 91% of readers found this page helpful

Author information

Name: Trent Wehner

Birthday: 1993-03-14

Address: 872 Kevin Squares, New Codyville, AK 01785-0416

Phone: +18698800304764

Job: Senior Farming Developer

Hobby: Paintball, Calligraphy, Hunting, Flying disc, Lapidary, Rafting, Inline skating

Introduction: My name is Trent Wehner, I am a talented, brainy, zealous, light, funny, gleaming, attractive person who loves writing and wants to share my knowledge and understanding with you.