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

AMC Comes Into Upfront With Bite, New Ways to Work With Advertisers

April 30, 2026

15 Tips to Write a Bio That Attracts Followers

April 30, 2026

For Creators – Building a Media Kit That Actually Gets Responses – GRIN

April 30, 2026
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

How AI Efficiency Is Subtly Disrupting The Interactions That Build Strong Teams — Smashing Magazine

April 29, 2026

20+ Top Kinetic Fonts for Energetic Designs

April 28, 2026

10 Best WordPress Developer Hosting Packages in 2026 in 2025 — Speckyboy

April 27, 2026

95 Greatest Fonts for Posters 2026

April 25, 2026
Leave A Reply Cancel Reply

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

AMC Comes Into Upfront With Bite, New Ways to Work With Advertisers

By adminApril 30, 20260

From an expanded holiday Sphere partnership to a live event for The Vampire Lestat, AMC…

15 Tips to Write a Bio That Attracts Followers

April 30, 2026

For Creators – Building a Media Kit That Actually Gets Responses – GRIN

April 30, 2026

Can a fake brand win in AI search? New experiment says yes

April 29, 2026

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

AMC Comes Into Upfront With Bite, New Ways to Work With Advertisers

April 30, 2026

15 Tips to Write a Bio That Attracts Followers

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

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