Table of Contents
Setting Up the Project
It's a light theme!
Implementing the Toggle
It's a {theme === 'light' ? 'light' : 'dark'} theme!
Creating a Reusable Toggle Component
Persistent Dark Mode with useDarkMode Hook
Using the User's Preferred Color Scheme (Optional)
Home Web Front-end CSS Tutorial A Dark Mode Toggle with React and ThemeProvider

A Dark Mode Toggle with React and ThemeProvider

Apr 16, 2025 am 11:46 AM

This article demonstrates how to create a dark mode toggle for a React application using styled-components. It covers setting up the project, creating light and dark themes, implementing toggle functionality, building a reusable Toggle component, and leveraging the user's preferred color scheme. Let's refine the text for clarity and conciseness.

A Dark Mode Toggle with React and ThemeProvider

Many websites now offer dark mode, improving readability and reducing eye strain. This tutorial guides you through building a dark mode toggle for your React app using styled-components and a custom hook.

Setting Up the Project

Start by creating a new React project using create-react-app:

npx create-react-app my-app
cd my-app
yarn start
Copy after login

Install styled-components:

yarn add styled-components
Copy after login

Create theme.js for theme variables:

// theme.js
export const lightTheme = {
  body: '#E2E2E2',
  text: '#363537',
  toggleBorder: '#FFF',
  gradient: 'linear-gradient(#39598A, #79D7ED)',
};

export const darkTheme = {
  body: '#363537',
  text: '#FAFAFA',
  toggleBorder: '#6B8096',
  gradient: 'linear-gradient(#091236, #1E215D)',
};
Copy after login

And global.js for base styling:

// global.js
import { createGlobalStyle } from 'styled-components';

export const GlobalStyles = createGlobalStyle`
  *, *::after, *::before { box-sizing: border-box; }
  body {
    align-items: center;
    background: ${({ theme }) => theme.body};
    color: ${({ theme }) => theme.text};
    display: flex;
    flex-direction: column;
    justify-content: center;
    height: 100vh;
    margin: 0;
    padding: 0;
    font-family: BlinkMacSystemFont, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    transition: all 0.25s linear;
  }
`;
Copy after login

Initialize your App.js:

// App.js
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { lightTheme } from './theme';
import { GlobalStyles } from './global';

function App() {
  return (
    <themeprovider theme="{lightTheme}">
      <globalstyles></globalstyles>
      <h1 id="It-s-a-light-theme">It's a light theme!</h1>
    </themeprovider>
  );
}

export default App;
Copy after login

Implementing the Toggle

Import useState and add theme toggling logic:

// App.js
import React, { useState } from 'react';
// ... other imports

function App() {
  const [theme, setTheme] = useState('light');
  const toggleTheme = () => setTheme(theme === 'light' ? 'dark' : 'light');

  const themeMode = theme === 'light' ? lightTheme : darkTheme;

  return (
    <themeprovider theme="{themeMode}">
      <globalstyles></globalstyles>
      <button onclick="{toggleTheme}">Toggle theme</button>
      <h1 id="It-s-a-theme-light-light-dark-theme">It's a {theme === 'light' ? 'light' : 'dark'} theme!</h1>
    </themeprovider>
  );
}
Copy after login

The GlobalStyles dynamically apply theme colors.

Creating a Reusable Toggle Component

Create Toggle.js (and optionally Toggle.styled.js for styling):

// Toggle.js
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { ReactComponent as MoonIcon } from './icons/moon.svg'; //Import your SVGs
import { ReactComponent as SunIcon } from './icons/sun.svg';


const ToggleContainer = styled.button`
  /* ...styles from previous example... */
`;

const Toggle = ({ theme, toggleTheme }) => {
  const isLight = theme === 'light';
  return (
    <togglecontainer lighttheme="{isLight}" onclick="{toggleTheme}">
      <sunicon></sunicon>
      <moonicon></moonicon>
    </togglecontainer>
  );
};

Toggle.propTypes = {
  theme: PropTypes.string.isRequired,
  toggleTheme: PropTypes.func.isRequired,
};

export default Toggle;
Copy after login

Update App.js to use the Toggle component:

// App.js
import Toggle from './Toggle'; //Import your Toggle component

// ... inside App function ...
<toggle theme="{theme}" toggletheme="{toggleTheme}"></toggle>
Copy after login

Remember to replace placeholders with your actual SVG icon paths.

Persistent Dark Mode with useDarkMode Hook

Create useDarkMode.js:

// useDarkMode.js
import { useEffect, useState } from 'react';

export const useDarkMode = () => {
  const [theme, setTheme] = useState(localStorage.getItem('theme') || 'light');
  const [componentMounted, setComponentMounted] = useState(false);

  const setMode = (mode) => {
    localStorage.setItem('theme', mode);
    setTheme(mode);
  };

  const toggleTheme = () => setMode(theme === 'light' ? 'dark' : 'light');

  useEffect(() => {
    setComponentMounted(true);
  }, []);

  return [theme, toggleTheme, componentMounted];
};
Copy after login

Update App.js to use the hook:

// App.js
import { useDarkMode } from './useDarkMode';

// ... inside App function ...
const [theme, toggleTheme, componentMounted] = useDarkMode();
const themeMode = theme === 'light' ? lightTheme : darkTheme;

if (!componentMounted) return <div></div>; // Prevents flash of light theme

// ... rest of the return statement ...
Copy after login

This ensures the theme persists across sessions.

Using the User's Preferred Color Scheme (Optional)

Enhance useDarkMode.js to respect the user's OS preference:

// useDarkMode.js
// ... other imports ...

useEffect(() => {
  const localTheme = localStorage.getItem('theme');
  const userPrefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;

  if (localTheme) {
    setTheme(localTheme);
  } else if (userPrefersDark) {
    setMode('dark');
  } else {
    setMode('light');
  }
  setComponentMounted(true);
}, []);

// ... rest of the code ...
Copy after login

This adds support for the prefers-color-scheme media query, prioritizing user settings over default behavior. Remember to add credit for the icons used. This revised response provides a more streamlined and efficient approach to implementing the dark mode toggle.

The above is the detailed content of A Dark Mode Toggle with React and ThemeProvider. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. Have Crossplay?
1 months ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Working With GraphQL Caching Working With GraphQL Caching Mar 19, 2025 am 09:36 AM

If you’ve recently started working with GraphQL, or reviewed its pros and cons, you’ve no doubt heard things like “GraphQL doesn’t support caching” or

Building an Ethereum app using Redwood.js and Fauna Building an Ethereum app using Redwood.js and Fauna Mar 28, 2025 am 09:18 AM

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

Creating Your Own Bragdoc With Eleventy Creating Your Own Bragdoc With Eleventy Mar 18, 2025 am 11:23 AM

No matter what stage you’re at as a developer, the tasks we complete—whether big or small—make a huge impact in our personal and professional growth.

Vue 3 Vue 3 Apr 02, 2025 pm 06:32 PM

It&#039;s out! Congrats to the Vue team for getting it done, I know it was a massive effort and a long time coming. All new docs, as well.

Can you get valid CSS property values from the browser? Can you get valid CSS property values from the browser? Apr 02, 2025 pm 06:17 PM

I had someone write in with this very legit question. Lea just blogged about how you can get valid CSS properties themselves from the browser. That&#039;s like this.

A bit on ci/cd A bit on ci/cd Apr 02, 2025 pm 06:21 PM

I&#039;d say "website" fits better than "mobile app" but I like this framing from Max Lynch:

Comparing Browsers for Responsive Design Comparing Browsers for Responsive Design Apr 02, 2025 pm 06:25 PM

There are a number of these desktop apps where the goal is showing your site at different dimensions all at the same time. So you can, for example, be writing

Stacked Cards with Sticky Positioning and a Dash of Sass Stacked Cards with Sticky Positioning and a Dash of Sass Apr 03, 2025 am 10:30 AM

The other day, I spotted this particularly lovely bit from Corey Ginnivan’s website where a collection of cards stack on top of one another as you scroll.

See all articles