Light and Dark mode using bootstrap - super easy guide 🌛

Hey guys, it’s been a while since I last wrote in this amazing community, I’ve been pretty busy with family stuff and developing some complex projects, with and without Wappler.
But I’ve been reading here some very interesting topics that have helped me at times to solve some technical problems so I think it’s always good to give back.

Dark mode is one of the most necessary features of the web. Many people prefer it because it is easy on the eyes.

60b6da3e1397b1ef10a968b3d172803d

In this tutorial you will learn how to use Wappler to detect when the system dark mode is enabled, and change the colors of the page accordingly without writing a single line of css and using bootstrap 5.3.0

Most modern browsers change their color scheme according to the operating system theme. This tutorial assumes that your browser falls into this category.

The demonstration will be using a switch and also a JS code that will allow us to match the mode that your system has active, whether your are using, windows or mac.

Step 1

It is necessary that you have the latest version of bootstrap, in this case 5.3.0 alpha 1, otherwise it will not work for you.
We can use the CDN:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384- GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous" />

Just copy and paste that into the head of your document.
An important point is that if you replace the bootstrap 5 link that wappler uses then wappler will not show in the app structure that bootstrap is installed, so I recommend pasting it after the link that wappler generates from bootstrap 5. Then you can remove the wappler bootstrap link in production.
Remember that version 5.3.0 is in alpha mode so use it at your own risk.
If you don’t want to use the CDN you can download the bootstrap files.

Step 2

Color mode styles are controlled by the data-bs-theme attribute. This attribute can be applied to the <html> element, or to any other element or Bootstrap component. If applied to the <html> element, it will apply to everything. If applied to a component or element, it will be scoped to that specific component or element.

In this case I chose to put the code inside the body as follows:

<body is="dmx-app" id="darkmodetest" dmx-bind:data-bs-theme="input1.value">

The input1 has to do with our next step where we will create an on and off switch for our dark mode.

Step 3

Create a Custom Switch Form group. You can rename it as you like in this example we will leave the name as input1
Now we need to add the following attribute to the switch:

dmx-bind:value="checked.then('dark', 'light')"

Step 4

In order to detect if we are in dark mode or not we use window.matchMedia('(prefers-color-scheme: dark)').matches
This will return true if dark mode is enabled.
So I wrote a JS function using this information:

<script>
        function setColorScheme() {
            if (window.matchMedia &&
            window.matchMedia('(prefers-color-scheme: dark)').matches) {
            dmx.app.set('lightmode', "dark");
            }
            else {
            dmx.app.set('lightmode', "light");
            }
            }
    </script>

U can copy paste this code at the end of your body or put it in a JS file.

Step 5

We need to add a pageflow to our page so that it calls the function we just wrote:

<script is="dmx-flow" id="flow1" type="text/dmx-flow" autorun>{
  runJS: {function: "setColorScheme", name: "setColorScheme"}
}</script>

Don’t forget to check the autorun!

Step 6

Finally we go back to our Switch and add the following attribute:

dmx-bind:checked="lightmode=='dark'"

So the page will go dark automatically when you load the site.

Grabación de pantalla 2022-12-26 a la(s) 23.38.00

And that’s how easy you can have dark mode in your web app with wappler.

Surely the Wappler team will incorporate this new feature in the future but since it is an alpha version of bootstrap, it may take months for it to be implemented so you can use it now :grin:.

BonusTrack

Here u have the entire code of my page in Wappler so u can play with it:

<!doctype html>
<html>

<head>
    <meta name="ac:base" content="/test">
    <base href="/test/">
    <script src="dmxAppConnect/dmxAppConnect.js"></script>
    <meta charset="UTF-8">
    <title>divide</title>
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js" integrity="sha256-CutOzxCRucUsn6C6TcEYsauvvYilEniTXldPa6/wu0k=" crossorigin="anonymous"></script>


    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel="stylesheet" href="estilos2.css" />
    <script src="dmxAppConnect/dmxImageParallax/dmxImageParallax.js" defer></script>
    <link rel="stylesheet" href="https://unpkg.com/@fullcalendar/core@4.4.2/main.min.css" />
    <script src="https://unpkg.com/@fullcalendar/core@4.4.2/main.min.js" defer></script>
    <script src="https://unpkg.com/@fullcalendar/core@4.4.2/locales-all.min.js" defer></script>
    <script src="https://unpkg.com/@fullcalendar/interaction@4.4.2/main.min.js" defer></script>
    <script src="https://unpkg.com/@fullcalendar/daygrid@4.4.2/main.min.js" defer></script>
    <script src="dmxAppConnect/dmxCalendar/dmxCalendar.js" defer></script>
    <script src="https://unpkg.com/@fullcalendar/google-calendar@4.4.2/main.min.js" defer></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous" />
    <script src="dmxAppConnect/dmxFormatter/dmxFormatter.js" defer></script>
</head>

<body is="dmx-app" id="dividescreen" dmx-bind:data-bs-theme="input1.value">
    <script is="dmx-flow" id="flow1" type="text/dmx-flow" autorun>{
  runJS: {function: "setColorScheme", name: "setColorScheme"}
}</script>
    <dmx-value id="var1"></dmx-value>
    <div class="container mt-3">
        <div class="row justify-content-center text-uppercase">
            <div class="col-4">
                <div class="form-group mb-3">
                    <legend class="col-sm-2 col-form-label">One switch</legend>
                    <div class="form-check form-switch" style="">
                        <input class="form-check-input" type="checkbox" value="" id="input1" name="input1" dmx-bind:value="checked.then('dark', 'light')" dmx-bind:checked="lightmode=='dark'" style="height: 20px; width: 40px;">
                        <label class="form-check-label" for="input1">&nbsp;Light switch&nbsp;</label>
                    </div>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col">
                <h4 class="text-center">{{lightmode}} mode On</h4>
            </div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    <script>
        function setColorScheme() {
            if (window.matchMedia &&
            window.matchMedia('(prefers-color-scheme: dark)').matches) {
            dmx.app.set('lightmode', "dark");
            }
            else {
            dmx.app.set('lightmode', "light");
            }
            }
    </script>
</body>

</html>
15 Likes

Awesome, thanks Max.

1 Like

What a great read - thanks for posting @Max_Saravia …!

1 Like

Seen as this just got auto bumped I’ll drop the current newest alpha version CDN links here incase anyone decides they want to give this ago. This is Bootstrap 5.3.0 Alpha 3:

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
1 Like

Thanks to @Max_Saravia, who gave me the idea to create an extension for Wappler.

2 Likes

Dark mode switcher is now available in Wappler: