DEV Community

Cover image for Dark Mode: Conditional Styling using styled-components
Nikhil Singh
Nikhil Singh

Posted on • Updated on

Dark Mode: Conditional Styling using styled-components

The styled-components allows you to write actual CSS code to style your components. It also removes the mapping between components and styles โ€“ using components as a low-level styling construct could not be easier. Here the official docs of styled-components

Getting Started

For the prerequisite part, you need to have Node already installed on your machine.

Next let's create a react app and install styled-components too and then start the application.

npx create-react-app react-app
cd react-app
npm install styled-components
npm start
Enter fullscreen mode Exit fullscreen mode

Let's Code

We need to import styled from "styled-components", and we need to create a Container component that will render an div tag. The Container component will act as a wrapper component

import styled from "styled-components";

const Container = styled.div`
//CSS to be added here
`
Enter fullscreen mode Exit fullscreen mode

To add the button to switch between the dark mode we will using a toggle button created using a check box.

<Container>
      <div className="contain">
        <h5>Dark Mode</h5>
        <label class="switch">
        <input type="checkbox" onChange={(e) => setDark(!dark)} />
        <span class="slider round"></span>
        </label>
      </div>
    </Container>
Enter fullscreen mode Exit fullscreen mode

CSS for the toggle button:

.contain {
    margin: auto;
    position: relative;
    top: 40%;
  }

  h5 {
    margin: 0;
  }
  .switch input {
    opacity: 0;
    width: 0;
    height: 0;
  }

  .slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: black;
    -webkit-transition: 0.4s;
    transition: 0.4s;
  }

  .slider:before {
    position: absolute;
    content: "";
    height: 14px;
    width: 14px;
    left: 2px;
    bottom: 1px;
    background-color: white;
    -webkit-transition: 0.4s;
    transition: 0.4s;
  }

  input:checked + .slider {
    background-color: white;
  }

  input:focus + .slider {
    box-shadow: 0 0 1px white;
  }

  input:checked + .slider:before {
    -webkit-transform: translateX(26px);
    -ms-transform: translateX(26px);
    transform: translateX(12px);
    background-color: black;
  }

  .slider.round {
    border-radius: 34px;
  }

  .slider.round:before {
    border-radius: 50%;
  }
Enter fullscreen mode Exit fullscreen mode

So this is how the toggle button would look like,
image

Now let's add the functionality, we will be using useState Hook,

  const [dark, setDark] = useState(false);
Enter fullscreen mode Exit fullscreen mode

By default the toggle should be off and when toggled the dark value should be true, so let's add onChange property on the input tag,

  <input type="checkbox" onChange={(e) => setDark(!dark)} />

Enter fullscreen mode Exit fullscreen mode

Next we need to pass the dark value to the Container component so that we can change the background color accordingly

<Container dark={dark}>
Enter fullscreen mode Exit fullscreen mode

After passing dark value we can change the background conditionally

const Container = styled.div`
  background: ${({ dark }) => (dark ? "black" : "white")}; //Conditional styling the background color
  height: 100vh;
  min-height: fit-content;
  .switch {
    position: relative;
    display: inline-block;
    width: 32px;
    height: 16px;
    border-radius: 50%;
    border: 3px solid black;
  }

  h5 {
    margin: 0;
    color: ${({ dark }) => (!dark ? "black" : "white")}; // To change the color of the text opposite to the background color
  }

//Remaining CSS remains the same
Enter fullscreen mode Exit fullscreen mode

The entire code:

import React, { useState } from "react";
import styled from "styled-components";

const Container = styled.div`
  background: ${({ dark }) => (dark ? "black" : "white")};
  height: 100vh;
  min-height: fit-content;
  .switch {
    position: relative;
    display: inline-block;
    width: 32px;
    height: 16px;
    border-radius: 50%;
    border: 3px solid black;
  }

  .contain {
    margin: auto;
    position: relative;
    top: 40%;
  }

  h5 {
    margin: 0;
    color: ${({ dark }) => (!dark ? "black" : "white")};
  }
  .switch input {
    opacity: 0;
    width: 0;
    height: 0;
  }

  .slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: black;
    -webkit-transition: 0.4s;
    transition: 0.4s;
  }

  .slider:before {
    position: absolute;
    content: "";
    height: 14px;
    width: 14px;
    left: 2px;
    bottom: 1px;
    background-color: white;
    -webkit-transition: 0.4s;
    transition: 0.4s;
  }

  input:checked + .slider {
    background-color: white;
  }

  input:focus + .slider {
    box-shadow: 0 0 1px white;
  }

  input:checked + .slider:before {
    -webkit-transform: translateX(26px);
    -ms-transform: translateX(26px);
    transform: translateX(12px);
    background-color: black;
  }

  .slider.round {
    border-radius: 34px;
  }

  .slider.round:before {
    border-radius: 50%;
  }
`;

function App() {
  const [dark, setDark] = useState(false);
  return (
    <Container dark={dark}>
      <div className="contain">
        <h5>Dark Mode</h5>
        <label class="switch">
          <input type="checkbox" onChange={(e) => setDark(!dark)} />
          <span class="slider round"></span>
        </label>
      </div>
    </Container>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

image

This is my first blog on Dev.to.
Hope it was helpful and easy to implement.
Will be looking forward for feedback on this, also check out my Github thenickrj

Discussion (7)

Collapse
hamidb80 profile image
hamid

Hey, i dont understand what's wrong with adding a class to that element rather than processing a huge string to just tweak a color...

Collapse
thenickrj profile image
Nikhil Singh Author

There's nothing wrong in adding a class, the idea here is instead of having conditional statement for a class we can directly have a condition for a specific CSS property instead of having different classes

Collapse
sharansharma94 profile image
sharansharma94

Wanted to know the same

Collapse
mohitm15 profile image
Mohit Maroliya • Edited

Nice article.

There's a correction required in the paragraph.

Next we did to pass the dark value to the Container component so that we can **CHANGE** background color accordingly

Collapse
thenickrj profile image
Nikhil Singh Author

Yeah Changed it! Thank You

Collapse
jreegene profile image
Jeremiah

Great article

Collapse
higorroberto profile image
higorteodoro

Show