Close Menu
Trendswave MediaTrendswave Media
  • Home
  • About Us
    • Contact Us
  • Services
  • Influencer Marketing
  • Marketing
  • SEO
  • Social Media
  • Web Design
  • Shop

Subscribe to Updates

Get the latest creative news from Trendswave about Marketing, SEO & Web Design.

Please enable JavaScript in your browser to complete this form.
Loading
What's Hot

Driving Qualified Leads With LinkedIn Content: A Proven Formula

October 3, 2025

Google Ads copywriting with AI: Getting the prompt right

October 3, 2025

A Practical Guide To Building With Clarity (Part 2) — Smashing Magazine

October 3, 2025
Facebook X (Twitter) Instagram
Trendswave MediaTrendswave Media
  • Home
  • About Us
    • Contact Us
  • Services
  • Influencer Marketing
  • Marketing
  • SEO
  • Social Media
  • Web Design
  • Shop
Trendswave MediaTrendswave Media
Home»Web Design»Build a light/dark mode toggle switch component with CSS & JavaScript
Web Design

Build a light/dark mode toggle switch component with CSS & JavaScript

adminBy adminFebruary 14, 2025No Comments5 Mins Read
Facebook Twitter Pinterest LinkedIn Tumblr WhatsApp VKontakte Email
Build a light/dark mode toggle switch component with CSS & JavaScript
Share
Facebook Twitter LinkedIn Pinterest Email


In this new tutorial, we’ll use previous knowledge and learn how to build a light/dark mode toggle switch component. This is a handy feature available in many sites and apps nowadays because it can help reduce eye strain and therefore improves accessibility.

MDN's color modesMDN's color modesMDN's color modes
MDN’s color modes

Slack's color modesSlack's color modesSlack's color modes
Slack’s color modes

It’s also worth noting that more and more CSS frameworks have started providing this functionality by default.

Bootstrap's dark modeBootstrap's dark modeBootstrap's dark mode
Bootstrap’s color modes

Tailwind's dark modeTailwind's dark modeTailwind's dark mode
Tailwind’s dark mode

What we’re building

Here’s an introductory video to give you a taste of the functionality that we want to achieve:


And, of course, there’s the CodePen demo for you to fork and play with:

To speed up the development process, we’ll heavily use markup and styles from a previous tutorial. In that tutorial, we developed a toggle switch component using the old-school CSS Checkbox hack technique.

1. Begin with the page markup

Our page will support light and dark modes. By default, the light mode will be active. 

Regarding the markup, we’ll need three radio buttons in total. When the third radio button (Auto) is active, the page colors will depend on the color scheme set in our OS settings. 

Our light/dark mode toggle componentOur light/dark mode toggle componentOur light/dark mode toggle component

Setting up dark mode in Windows 11 Setting up dark mode in Windows 11 Setting up dark mode in Windows 11
Setting up dark mode in Windows 11

Here’s the required structure:

2. Add the CSS

We’ll define the initial page colors using CSS variables. 

1
:root {
2
  ...
3
  --white: #fff;
4
  --black: black;
5
  --text-color: var(--black);
6
  --bg-color: var(--white);
7
  ...
8
}

Then, as soon as the dark mode is enabled, we’ll override the values of these variables.

1
.theme-dark {
2
  color-scheme: dark;
3
  --text-color: #fff;
4
  --bg-color: black;
5
  ...
6
}

Notice the color-scheme: dark property value that allows browsers to render native elements in dark mode (e.g. form controls).

Of course, we can go even further from here. For example, we can have different image filters depending on the active mode, etc.

Below you can see the styles responsible for creating the look and feel of our toggle switches.

1
/*CUSTOM VARIABLES HERE*/
2

3
.switches {
4
  display: inline-block;
5
  padding: 0;
6
  border: 1px solid var(--gray);
7
  margin: 10px 0 0;
8
  border-radius: 6px;
9
}
10

11
.switches li {
12
  position: relative;
13
}
14

15
.switches li:not(:last-child) {
16
  border-bottom: 1px solid var(--gray);
17
}
18

19
.switches li [type="radio"] {
20
  position: absolute;
21
  left: -9999px;
22
}
23

24
.switches label {
25
  display: grid;
26
  grid-template-columns: 40px auto;
27
  align-items: center;
28
  gap: 10px;
29
  padding: 20px;
30
  cursor: pointer;
31
}
32

33
.switches span {
34
  flex-shrink: 0;
35
}
36

37
.switches span:empty {
38
  position: relative;
39
  width: 50px;
40
  height: 26px;
41
  border-radius: 15px;
42
  background: var(--gray);
43
  transition: all 0.3s;
44
}
45

46
.switches span:empty::before,
47
.switches span:empty::after {
48
  content: "";
49
  position: absolute;
50
}
51

52
.switches span:empty::before {
53
  top: 1px;
54
  left: 1px;
55
  width: 24px;
56
  height: 24px;
57
  background: var(--slate-gray);
58
  border-radius: 50%;
59
  z-index: 1;
60
  transition: transform 0.3s;
61
}
62

63
.switches span:empty::after {
64
  top: 50%;
65
  transform: translateY(-50%);
66
  width: 14px;
67
  height: 14px;
68
  left: 6px;
69
  background-size: 14px 14px;
70
}
71

72
.switches [type="radio"]:checked + label span:empty {
73
  background: var(--white-pearl);
74
}
75

76
.switches [type="radio"]:checked + label span:empty::before {
77
  transform: translateX(24px);
78
}
79

80
.switches li:nth-child(1) [type="radio"]:checked + label span:empty::after {
81
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48IS0tIUZvbnQgQXdlc29tZSBGcmVlIDYuNy4yIGJ5IEBmb250YXdlc29tZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tIExpY2Vuc2UgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbS9saWNlbnNlL2ZyZWUgQ29weXJpZ2h0IDIwMjQgRm9udGljb25zLCBJbmMuLS0+PHBhdGggZD0iTTM2MS41IDEuMmM1IDIuMSA4LjYgNi42IDkuNiAxMS45TDM5MSAxMjFsMTA3LjkgMTkuOGM1LjMgMSA5LjggNC42IDExLjkgOS42czEuNSAxMC43LTEuNiAxNS4yTDQ0Ni45IDI1Nmw2Mi4zIDkwLjNjMy4xIDQuNSAzLjcgMTAuMiAxLjYgMTUuMnMtNi42IDguNi0xMS45IDkuNkwzOTEgMzkxIDM3MS4xIDQ5OC45Yy0xIDUuMy00LjYgOS44LTkuNiAxMS45cy0xMC43IDEuNS0xNS4yLTEuNkwyNTYgNDQ2LjlsLTkwLjMgNjIuM2MtNC41IDMuMS0xMC4yIDMuNy0xNS4yIDEuNnMtOC42LTYuNi05LjYtMTEuOUwxMjEgMzkxIDEzLjEgMzcxLjFjLTUuMy0xLTkuOC00LjYtMTEuOS05LjZzLTEuNS0xMC43IDEuNi0xNS4yTDY1LjEgMjU2IDIuOCAxNjUuN2MtMy4xLTQuNS0zLjctMTAuMi0xLjYtMTUuMnM2LjYtOC42IDExLjktOS42TDEyMSAxMjEgMTQwLjkgMTMuMWMxLTUuMyA0LjYtOS44IDkuNi0xMS45czEwLjctMS41IDE1LjIgMS42TDI1NiA2NS4xIDM0Ni4zIDIuOGM0LjUtMy4xIDEwLjItMy43IDE1LjItMS42ek0xNjAgMjU2YTk2IDk2IDAgMSAxIDE5MiAwIDk2IDk2IDAgMSAxIC0xOTIgMHptMjI0IDBhMTI4IDEyOCAwIDEgMCAtMjU2IDAgMTI4IDEyOCAwIDEgMCAyNTYgMHoiLz48L3N2Zz4=");
82
}
83

84
.switches li:nth-child(2) [type="radio"]:checked + label span:empty::after {
85
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzODQgNTEyIj48IS0tIUZvbnQgQXdlc29tZSBGcmVlIDYuNy4yIGJ5IEBmb250YXdlc29tZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tIExpY2Vuc2UgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbS9saWNlbnNlL2ZyZWUgQ29weXJpZ2h0IDIwMjQgRm9udGljb25zLCBJbmMuLS0+PHBhdGggZD0iTTIyMy41IDMyQzEwMCAzMiAwIDEzMi4zIDAgMjU2UzEwMCA0ODAgMjIzLjUgNDgwYzYwLjYgMCAxMTUuNS0yNC4yIDE1NS44LTYzLjRjNS00LjkgNi4zLTEyLjUgMy4xLTE4LjdzLTEwLjEtOS43LTE3LTguNWMtOS44IDEuNy0xOS44IDIuNi0zMC4xIDIuNmMtOTYuOSAwLTE3NS41LTc4LjgtMTc1LjUtMTc2YzAtNjUuOCAzNi0xMjMuMSA4OS4zLTE1My4zYzYuMS0zLjUgOS4yLTEwLjUgNy43LTE3LjNzLTcuMy0xMS45LTE0LjMtMTIuNWMtNi4zLS41LTEyLjYtLjgtMTktLjh6Ii8+PC9zdmc+");
86
}
87

88
.switches li:nth-child(3) [type="radio"]:checked + label span:empty::after {
89
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48IS0tIUZvbnQgQXdlc29tZSBGcmVlIDYuNy4yIGJ5IEBmb250YXdlc29tZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tIExpY2Vuc2UgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbS9saWNlbnNlL2ZyZWUgQ29weXJpZ2h0IDIwMjQgRm9udGljb25zLCBJbmMuLS0+PHBhdGggZD0iTTQ0OCAyNTZjMC0xMDYtODYtMTkyLTE5Mi0xOTJsMCAzODRjMTA2IDAgMTkyLTg2IDE5Mi0xOTJ6TTAgMjU2YTI1NiAyNTYgMCAxIDEgNTEyIDBBMjU2IDI1NiAwIDEgMSAwIDI1NnoiLz48L3N2Zz4=");
90
}

3. Add the JavaScript

To set up the functionality for our toggle switch component, we’ll take advantage of the local storage and the prefers-color-scheme CSS media feature. This useful media query takes as value the user’s preferred selection as defined in their OS settings. 

The presence of the theme-dark class in the html element will denote that we’ve requested the dark mode manually or through the system settings.

The dark mode enabledThe dark mode enabledThe dark mode enabled

At that point, we’ll store in local storage, the dark-mode="true" key value that will help us keep the user’s color scheme selection on page reload.

The value stored in local storageThe value stored in local storageThe value stored in local storage

We’ll also store a second key value for identifying the active toggle switch.

Store in local storage the active radio buttonStore in local storage the active radio buttonStore in local storage the active radio button

With all these in mind, here’s all the required JavaScript—use your browser to check how it works:

1
const html = document.documentElement;
2
const switches = document.querySelector(".switches");
3
const inputs = switches.querySelectorAll("input");
4

5
if (localStorage.getItem("dark-mode")) {
6
  html.classList.add("theme-dark");
7
}
8

9
if (localStorage.getItem("selected-radio")) {
10
  switches.querySelector(`#${localStorage.getItem("selected-radio")}`).checked =
11
    "true";
12
}
13

14
const setTheme = (theme) => {
15
  if (theme === "dark") {
16
    html.classList.add("theme-dark");
17
    localStorage.setItem("dark-mode", "true");
18
  } else {
19
    html.classList.remove("theme-dark");
20
    localStorage.removeItem("dark-mode");
21
  }
22
};
23

24
const handleMediaChange = (e) => {
25
  if (switches.querySelector('[type="radio"]:checked').id === "auto") {
26
    setTheme(e.matches ? "dark" : "light");
27
  }
28
};
29

30
const handleInputChange = (e) => {
31
  const themeMode = e.target.id;
32
  if (
33
    themeMode === "dark" ||
34
    (themeMode === "auto" &&
35
      window.matchMedia("(prefers-color-scheme: dark)").matches)
36
  ) {
37
    setTheme("dark");
38
  } else {
39
    setTheme("light");
40
  }
41
  localStorage.setItem("selected-radio", themeMode);
42
};
43

44
window
45
  .matchMedia("(prefers-color-scheme: dark)")
46
  .addEventListener("change", handleMediaChange);
47

48
inputs.forEach((input) => input.addEventListener("input", handleInputChange));

Conclusion

Done! I hope you had some fun with this exercise and will consider this component whenever you need a light/dark theme toggle functionality.

Let’s remind ourselves of our creation:

As always, thanks a lot for reading!

More color modes tutorials

Need more color scheme tutorials? Check out the tutorials below:



Source link

Build component CSS JavaScript lightdark mode Switch toggle
Share. Facebook Twitter Pinterest LinkedIn Tumblr WhatsApp Email
Previous ArticleIs Manychat Officially Approved by Instagram?
Next Article Best 20 Content Creation Tools Every Creator Should Know
admin
  • Website

Related Posts

A Practical Guide To Building With Clarity (Part 2) — Smashing Magazine

October 3, 2025

Fresh Resources for Web Designers and Developers (September 2025)

October 2, 2025

Shades Of October (2025 Wallpapers Edition) — Smashing Magazine

October 1, 2025

Principles And Implementation (Part 1) — Smashing Magazine

September 29, 2025
Leave A Reply Cancel Reply

  • Facebook
  • Twitter
  • Pinterest
  • Instagram
  • YouTube
  • Vimeo
Don't Miss
Marketing

Driving Qualified Leads With LinkedIn Content: A Proven Formula

By adminOctober 3, 20250

Are you struggling to generate qualified leads from your LinkedIn content? Wondering how to transform…

Google Ads copywriting with AI: Getting the prompt right

October 3, 2025

A Practical Guide To Building With Clarity (Part 2) — Smashing Magazine

October 3, 2025

Meta unveils Business AI and new generative tools

October 2, 2025

Subscribe to Updates

Get the latest creative news from Trendswave about Marketing, SEO & Web Design.

Please enable JavaScript in your browser to complete this form.
Loading
About Us

Trendswave is an Influencer Marketing Agency with access to one of the largest influencer networks in the Poland, connecting brands and agencies to only the best influencers and social media thought leaders.

Our Picks

Driving Qualified Leads With LinkedIn Content: A Proven Formula

October 3, 2025

Google Ads copywriting with AI: Getting the prompt right

October 3, 2025
Quicklinks
  • Influencer Marketing
  • Marketing
  • SEO
  • Social Media
  • Web Design
  • About Us
  • Contact Us
  • Disclaimer
  • Privacy Policy
  • Terms and Conditions
© 2025 Trendswave.All Rights Reserved

Type above and press Enter to search. Press Esc to cancel.