Blog

Construct a lightweight/darkish mode toggle swap element with CSS & JavaScript

On this new tutorial, we’ll use earlier information and learn to construct a lightweight/darkish mode toggle swap element. This can be a helpful characteristic obtainable in lots of websites and apps these days as a result of it might assist scale back eye pressure and due to this fact improves accessibility.

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

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

It’s additionally price noting that increasingly CSS frameworks have began offering this performance by default.

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

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

What we’re constructing

Right here’s an introductory video to provide you a style of the performance that we wish to obtain:

And, in fact, there’s the CodePen demo so that you can fork and play with:

To hurry up the event course of, we’ll closely use markup and types from a earlier tutorial. In that tutorial, we developed a toggle swap element utilizing the old-school CSS Checkbox hack method.

1. Start with the web page markup

Our web page will help mild and darkish modes. By default, the sunshine mode can be energetic. 

Concerning the markup, we’ll want three radio buttons in complete. When the third radio button (Auto) is energetic, the web page colours will rely on the colour 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
Establishing darkish mode in Home windows 11

Right here’s the required construction:

1 class=“switches”>
2

  • 3 sort=“radio” id=“mild” identify=“theme-mode” checked>
    4 for=“mild”>
    5 Mild
    6
    7
    8

    9

  • 10 sort=“radio” id=“darkish” identify=“theme-mode”>
    11 for=“darkish”>
    12 Darkish
    13
    14
    15

    16

  • 17 sort=“radio” id=“auto” identify=“theme-mode”>
    18 for=“auto”>
    19 System
    20
    21
    22

    23

    2. Add the CSS

    We’ll outline the preliminary web page colours utilizing 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 quickly because the darkish mode is enabled, we’ll override the values of those variables.

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

    Discover the color-scheme: darkish property worth that permits browsers to render native parts in darkish mode (e.g. type controls).

    After all, we are able to go even farther from right here. For instance, we are able to have completely different picture filters relying on the energetic mode, and so forth.

    Under you may see the types accountable for creating the appear and feel of our toggle switches.

    1/*CUSTOM VARIABLES HERE*/
    2
    3.switches {
    4 show: inline-block;
    5 padding: 0;
    6 border: 1px strong var(–gray);
    7 margin: 10px 0 0;
    8 border-radius: 6px;
    9}
    10
    11.switches li {
    12 place: relative;
    13}
    14
    15.switches li:not(:last-child) {
    16 border-bottom: 1px strong var(–gray);
    17}
    18
    19.switches li [type=“radio”] {
    20 place: absolute;
    21 left: -9999px;
    22}
    23
    24.switches label {
    25 show: grid;
    26 grid-template-columns: 40px auto;
    27 align-items: heart;
    28 hole: 10px;
    29 padding: 20px;
    30 cursor: pointer;
    31}
    32
    33.switches span {
    34 flex-shrink: 0;
    35}
    36
    37.switches span:empty {
    38 place: relative;
    39 width: 50px;
    40 top: 26px;
    41 border-radius: 15px;
    42 background: var(–gray);
    43 transition: all 0.3s;
    44}
    45
    46.switches span:empty::earlier than,
    47.switches span:empty::after {
    48 content material: “”;
    49 place: absolute;
    50}
    51
    52.switches span:empty::earlier than {
    53 high: 1px;
    54 left: 1px;
    55 width: 24px;
    56 top: 24px;
    57 background: var(–slate-gray);
    58 border-radius: 50%;
    59 z-index: 1;
    60 transition: rework 0.3s;
    61}
    62
    63.switches span:empty::after {
    64 high: 50%;
    65 rework: translateY(-50%);
    66 width: 14px;
    67 top: 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::earlier than {
    77 rework: translateX(24px);
    78}
    79
    80.switches li:nth-child(1) [type=“radio”]:checked + label span:empty::after {
    81 background-image: url(“knowledge:picture/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48IS0tIUZvbnQgQXdlc29tZSBGcmVlIDYuNy4yIGJ5IEBmb250YXdlc29tZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tIExpY2Vuc2UgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbS9saWNlbnNlL2ZyZWUgQ29weXJpZ2h0IDIwMjQgRm9udGljb25zLCBJbmMuLS0+PHBhdGggZD0iTTM2MS41IDEuMmM1IDIuMSA4LjYgNi42IDkuNiAxMS45TDM5MSAxMjFsMTA3LjkgMTkuOGM1LjMgMSA5LjggNC42IDExLjkgOS42czEuNSAxMC43LTEuNiAxNS4yTDQ0Ni45IDI1Nmw2Mi4zIDkwLjNjMy4xIDQuNSAzLjcgMTAuMiAxLjYgMTUuMnMtNi42IDguNi0xMS45IDkuNkwzOTEgMzkxIDM3MS4xIDQ5OC45Yy0xIDUuMy00LjYgOS44LTkuNiAxMS45cy0xMC43IDEuNS0xNS4yLTEuNkwyNTYgNDQ2LjlsLTkwLjMgNjIuM2MtNC41IDMuMS0xMC4yIDMuNy0xNS4yIDEuNnMtOC42LTYuNi05LjYtMTEuOUwxMjEgMzkxIDEzLjEgMzcxLjFjLTUuMy0xLTkuOC00LjYtMTEuOS05LjZzLTEuNS0xMC43IDEuNi0xNS4yTDY1LjEgMjU2IDIuOCAxNjUuN2MtMy4xLTQuNS0zLjctMTAuMi0xLjYtMTUuMnM2LjYtOC42IDExLjktOS42TDEyMSAxMjEgMTQwLjkgMTMuMWMxLTUuMyA0LjYtOS44IDkuNi0xMS45czEwLjctMS41IDE1LjIgMS42TDI1NiA2NS4xIDM0Ni4zIDIuOGM0LjUtMy4xIDEwLjItMy43IDE1LjItMS42ek0xNjAgMjU2YTk2IDk2IDAgMSAxIDE5MiAwIDk2IDk2IDAgMSAxIC0xOTIgMHptMjI0IDBhMTI4IDEyOCAwIDEgMCAtMjU2IDAgMTI4IDEyOCAwIDEgMCAyNTYgMHoiLz48L3N2Zz4=”);
    82}
    83
    84.switches li:nth-child(2) [type=“radio”]:checked + label span:empty::after {
    85 background-image: url(“knowledge:picture/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(“knowledge:picture/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48IS0tIUZvbnQgQXdlc29tZSBGcmVlIDYuNy4yIGJ5IEBmb250YXdlc29tZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tIExpY2Vuc2UgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbS9saWNlbnNlL2ZyZWUgQ29weXJpZ2h0IDIwMjQgRm9udGljb25zLCBJbmMuLS0+PHBhdGggZD0iTTQ0OCAyNTZjMC0xMDYtODYtMTkyLTE5Mi0xOTJsMCAzODRjMTA2IDAgMTkyLTg2IDE5Mi0xOTJ6TTAgMjU2YTI1NiAyNTYgMCAxIDEgNTEyIDBBMjU2IDI1NiAwIDEgMSAwIDI1NnoiLz48L3N2Zz4=”);
    90}

    3. Add the JavaScript

    To arrange the performance for our toggle swap element, we’ll make the most of the native storage and the prefers-color-scheme CSS media characteristic. This handy media question takes as worth the person’s most well-liked choice as outlined of their OS settings. 

    The presence of the theme-dark class within the html ingredient will denote that we’ve requested the darkish mode manually or by the system settings.

    The dark mode enabledThe dark mode enabledThe dark mode enabled

    At that time, we’ll retailer in native storage, the dark-mode=”true” key worth that may assist us preserve the person’s colour scheme choice on web page reload.

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

    We’ll additionally retailer a second key worth for figuring out the energetic toggle swap.

    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 thoughts, right here’s all of the required JavaScript—use your browser to test the way it works:

    1const html = doc.documentElement;
    2const switches = doc.querySelector(.switches);
    3const inputs = switches.querySelectorAll(enter);
    4
    5if (localStorage.getItem(dark-mode)) {
    6 html.classList.add(theme-dark);
    7}
    8
    9if (localStorage.getItem(selected-radio)) {
    10 switches.querySelector(`#${localStorage.getItem(selected-radio)}`).checked =
    11 true;
    12}
    13
    14const setTheme = (theme) => {
    15 if (theme === darkish) {
    16 html.classList.add(theme-dark);
    17 localStorage.setItem(dark-mode, true);
    18 } else {
    19 html.classList.take away(theme-dark);
    20 localStorage.removeItem(dark-mode);
    21 }
    22};
    23
    24const handleMediaChange = (e) => {
    25 if (switches.querySelector([type=”radio”]:checked).id === auto) {
    26 setTheme(e.matches ? darkish : mild);
    27 }
    28};
    29
    30const handleInputChange = (e) => {
    31 const themeMode = e.goal.id;
    32 if (
    33 themeMode === darkish ||
    34 (themeMode === auto &&
    35 window.matchMedia((prefers-color-scheme: darkish)).matches)
    36 ) {
    37 setTheme(darkish);
    38 } else {
    39 setTheme(mild);
    40 }
    41 localStorage.setItem(selected-radio, themeMode);
    42};
    43
    44window
    45 .matchMedia((prefers-color-scheme: darkish))
    46 .addEventListener(change, handleMediaChange);
    47
    48inputs.forEach((enter) => enter.addEventListener(enter, handleInputChange));

    Conclusion

    Finished! I hope you had some enjoyable with this train and can contemplate this element everytime you want a lightweight/darkish theme toggle performance.

    Let’s remind ourselves of our creation:

    As all the time, thanks lots for studying!

    Extra colour modes tutorials

    Want extra colour scheme tutorials? Try the tutorials under: