DEV Community

loading...
Cover image for Light theme.. Swoosh! Dark Theme

Light theme.. Swoosh! Dark Theme

Temitope Ayodele
Frontend and Web Accessibility Engineer passionate about optimizing for web performance, user experience and accessibility.
・3 min read

Originally written on my blog.

Many people prefer to read on a dark screen, while others prefer the light mode. Giving users the ability to switch between these two modes is a great user experience feature. It is pretty easy to implement this in your code, and in this article, I will work you through how to do this in React using styled-components. I used this method to implement this on my portfolio website

To begin install styled-components

npm install styled-components
Enter fullscreen mode Exit fullscreen mode

You can check out documentation of styled-components

We will now create some components

1. Theme Component

This component will contain your preferred colors for dark mode and light mode.

// theme.js
export const lightTheme = {
  body: "#fffffe",
  header: "#094067",
  text: "#5f6c7b",
  button: "#3da9fc"
};
export const darkTheme = {
  body: "#094067",
  header: "#fffffe",
  text: "#d8eefe",
  button: "#3da9fc"
};
Enter fullscreen mode Exit fullscreen mode

2. Wrapping the app with ThemeProvider

To make this theme available to all pages, the component(in our case, App.js) is wrapped in the ThemeProvider. This way, all styled-components within the ThemeProvider has access to the provided theme, no matter how deep.

import { ThemeProvider } from "styled-components";
import { lightTheme, darkTheme } from "./theme";

///STYLED-COMPONENTS
import { H1, Layout, P } from "./styles";

export default function App() {
  return (
    <ThemeProvider theme={lightTheme}>
      <Layout>
        <H1>My Awesome App</H1>
        <P>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel....
        </P>
        <Button>Toggle mode</Button>
      </Layout>
    </ThemeProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the above snippet, we wrapped the component with the ThemeProvider and passed the lightTheme to the theme prop.

3. Create Global Stylesheet

With styled components, you can specify global styles that spans across your application. You do this by importing createGlobalStyle from styled-components. Now that our app is wrapped withing the ThemeProvider, every component within it now has access to the theme.

// GlobalStyles.js
import { createGlobalStyle} from "styled-components"
export const GlobalStyles = createGlobalStyle`
  body {
    background: ${({ theme }) => theme.body};
    color: ${({ theme }) => theme.text};
    font-family: Roboto, sans-serif;
    transition: all 0.4s linear;
  }
  `
Enter fullscreen mode Exit fullscreen mode

4. Accessing the theme prop for styled-components

We can also go ahead to defined colors on our styled-components using the theme props

// styles.js
import styled from "styled-components";

export const Layout = styled.div`
  width: 100%;
  height: 100vh;
  text-align: center;
  padding: 2%;
  box-sizing: border-box;
`;

export const H1 = styled.h1`
  font-size: 2rem;
  color: ${(props) => props.theme.header};
`;

export const P = styled.p`
  font-size: 1.2rem;
  color: ${(props) => props.theme.text};
`;

export const Button = styled.button`
  border: none;
  padding: 0.7rem 1rem;
  background: ${(props) => props.theme.button};
  border-radius: 5px;
  font-weight: 700;
  font-size: 1rem;
  color: ${(props) => props.theme.body};
`;
Enter fullscreen mode Exit fullscreen mode

TOGGLE BETWEEN LIGHT MODE AND DARKMODE

To toggle between the two modes, we can use a custom hook, called the useDarkMode.

// useDarkMode.js
import { useEffect, useState } from "react";
export const useDarkMode = () => {
  const [theme, setTheme] = useState("light");
  const [componentMounted, setComponentMounted] = useState(false);

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

  const toggleTheme = () => {
    if (theme === "light") {
      setMode("dark");
    } else {
      setMode("light");
    }
  };

  useEffect(() => {
    const localTheme = window.localStorage.getItem("theme");
    if (localTheme) {
      setTheme(localTheme);
    } else {
      setMode("light");
    }
    setComponentMounted(true);
  }, []);

  return [theme, toggleTheme, componentMounted];
};
Enter fullscreen mode Exit fullscreen mode
  • setMode saves the user's preferred theme in localStorage. This ensures that when the user selects a theme, the preferred choice persists even after the user leaves the app.
  • toggleTheme function toggles between light theme and dark theme
  • useEffect lifecycle hook checks on component mounting if there is a previuosly stored theme in the localStorage, if yes, the theme is set to that value. If there isn't the theme is set to light (or dark if you please)

Next we import this custom hook to the App.js

import React, { useEffect } from "react";
import { Button, H1, Layout, P } from "./styles";
import { ThemeProvider } from "styled-components";
import { lightTheme, darkTheme } from "./theme";
import { GlobalStyles } from "./GlobalStyles";
import { useDarkMode } from "./useDarkMode";

export default function App() {
//New
  const [theme, toggleTheme, componentMounted] = useDarkMode();
  useEffect(() => {
    if (!componentMounted) {
      return <div />;
    }
    // eslint-disable-next-line
  }, []);
//..New

  return (
    <ThemeProvider theme={theme === 'light' ? lightTheme : darkTheme}>
      <GlobalStyles />
      <Layout>
        <H1>My Awesome App</H1>
        <P>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel...
        </P>
        <Button onClick={() => toggleTheme()}>Toggle mode</Button>
      </Layout>
    </ThemeProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the above snippet, we imported the useDarkMode custom hook which returns the theme, the toggle functionallity and the componentMounted.

  • First, we confirm that the component has mounted using the useEffect lifecycle hook. If it hasn't, we render an empty div.
  • We add the toggleTheme functionality to the button, which toggles the theme onClick(light and dark mode),
  • then in the ThemeProvider, we dynamically render lightTheme or darkTheme based on the theme returned by the useDarkMode hook.

That is all! We can now easily toggle between the light mode and the darkmode. Below is the codesandbox for the full code.

Discussion (2)

Collapse
rishitkhandelwal profile image
Rishit Khandelwal

Light mode default... 😟πŸ₯ΊπŸ˜°πŸ˜¨πŸ˜’πŸ˜₯πŸ˜“πŸ˜±πŸ€―

Collapse
desoga profile image
deji adesoga

Lol. Tears of Joy!