Harness the power of Bootstrap 5.3 color modes based on the user's browser

It has come to my attention that Bootstrap 5.3 introduces support for a customizable color scheme, allowing me to personalize various key features.

Interestingly, the default dark theme now relies on the explicitly defined bs-theme data attribute rather than the prefers-color-scheme: dark property. This means that the browser's preferred theme setting is disregarded.

Should I update the <html>'s data-bs-theme with JavaScript upon page load and possibly store it in local storage, for instance?

const lsBsTheme = localStorage.getItem("bs-theme")
const bsTheme = lsBsTheme ||
  window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
document.querySelector("html").dataset.bsTheme = bsTheme
if (!lsBsTheme) localStorage.setItem("bs-theme", bsTheme)

This seems like a complex process. Is there a simpler alternative available?

Answer №1

If you are looking to exclusively focus on the prefers-color-scheme aspect, you have the option to customize Bootstrap with Sass and define the variable $color-mode-type: media-query;

In case the user needs the ability to switch between light and dark modes and have their choice saved, utilizing localStorage along with data attributes is recommended (as demonstrated in the question). The library does not have a built-in solution for this. The Bootstrap documentation includes a code snippet for implementation:

/*!
 * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
 * Copyright 2011-2023 The Bootstrap Authors
 * Licensed under the Creative Commons Attribution 3.0 Unported License.
 */

(() => {
  'use strict'

  const getStoredTheme = () => localStorage.getItem('theme')
  const setStoredTheme = theme => localStorage.setItem('theme', theme)

  const getPreferredTheme = () => {
    const storedTheme = getStoredTheme()
    if (storedTheme) {
      return storedTheme
    }

    return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
  }

  const setTheme = theme => {
    if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
      document.documentElement.setAttribute('data-bs-theme', 'dark')
    } else {
      document.documentElement.setAttribute('data-bs-theme', theme)
    }
  }

  setTheme(getPreferredTheme())

  const showActiveTheme = (theme, focus = false) => {
    const themeSwitcher = document.querySelector('#bd-theme')

    if (!themeSwitcher) {
      return
    }

    const themeSwitcherText = document.querySelector('#bd-theme-text')
    const activeThemeIcon = document.querySelector('.theme-icon-active use')
    const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
    const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')

    document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
      element.classList.remove('active')
      element.setAttribute('aria-pressed', 'false')
    })

    btnToActive.classList.add('active')
    btnToActive.setAttribute('aria-pressed', 'true')
    activeThemeIcon.setAttribute('href', svgOfActiveBtn)
    const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
    themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)

    if (focus) {
      themeSwitcher.focus()
    }
  }

  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
    const storedTheme = getStoredTheme()
    if (storedTheme !== 'light' && storedTheme !== 'dark') {
      setTheme(getPreferredTheme())
    }
  })

  window.addEventListener('DOMContentLoaded', () => {
    showActiveTheme(getPreferredTheme())

    document.querySelectorAll('[data-bs-theme-value]')
      .forEach(toggle => {
        toggle.addEventListener('click', () => {
          const theme = toggle.getAttribute('data-bs-theme-value')
          setStoredTheme(theme)
          setTheme(theme)
          showActiveTheme(theme, true)
        })
      })
  })
})()

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Problem with Ionic 2 local storage: struggling to store retrieved value in a variable

Struggling to assign the retrieved value from a .get function to a variable declared outside of it. var dt; //fetching data this.local.get('didTutorial').then((value) => { alert(value); dt = value; }) console.log("Local Storage value: " ...

Discontinuing the fieldset tab interface feature from a Dexterity content type

I am looking to modify a condition to prevent the loading of certain javascript code when inserting an object of my content type. The current condition works only when editing the object: <?xml version="1.0"?> <object name="portal_javascripts"> ...

Can someone explain how to implement Bootstrap 5 Popover in a react.js component?

Currently, I am incorporating Bootstrap 5 via CDN in my React project. I have a specific component where I intend to utilize the Popover feature. Following the documentation's instructions, it mentions that one must include popper.min.js before bootst ...

a guide to incorporating Google Maps into your website using latitude and longitude coordinates

After retrieving a list of latitudes and longitudes from my API for an AngularJS application, I want to display a Google map indicating the positions of these coordinates. I attempted using an iFrame but it only displayed a blank page since the latitudes ...

Struggling to spot my error (codewars, javascript, level 8)

Can You Translate?! After receiving a message on WhatsApp from an unfamiliar number, you wonder if it's from the person with a foreign accent you met last night. Your task is to write a simple function that checks for various translations of the word ...

The Highchart formatter function is being called twice on each occasion

My high chart has a formatter function that seems to be running twice. formatter: function() { console.log("starting formatter execution"); return this.value; } Check out the Fiddle for more details! ...

Struggling with updating state using splice method within an onClick event in React Hooks

CODE DEMO I'm facing an issue with my code snippet where it appears fine when I console.log it, but fails to set the state. The goal is to delete a box by using splice when clicked, however, something seems to be preventing it from working properly. ...

Using Angular routing without relying on a web server to load templates

Can templates be loaded in Angular without a web server? I came across an example here: https://groups.google.com/forum/#!topic/angular/LXzaAWqWEus but it seems to only print the template paths instead of their content. Is there a functioning example of t ...

Using ReactJS to incorporate events with an external DOM element

I am using ReactJS version 16.13.1 and I have the need to display an external DOM element along with its events. Let's consider having a <button type="button" id="testBtnSiri" onclick="alert('Functionality exists');">Testbutton Sir ...

I'm looking for a way to track the progress of an ajax call. Specifically, I want to know how I

I am currently working on an AJAX call that executes a lengthy PHP script producing 20 different results. I aim to display the progress of each step within the script, such as 1/20 complete, 2/20 complete, 3/20 complete. Last updated on 29-12-2015 at 03:1 ...

Event handler for "copy" on the iPad

Is it possible to bind an event handler to the copy event on iPad or iPhone devices? ...

transfer the output from the second selection to the adjacent div

I am utilizing a library called select2 specifically for single choice scenarios. My goal is to transfer the selected option to a different div once it has been chosen. Here is the code I have so far: https://jsfiddle.net/hxe7wr65/ Is there a way to ach ...

Tips for capturing a screenshot of the ESRI Map using Angular

Is there a way to capture a screenshot of the Esri map in its current state on the UI and then convert it into a PDF for download using Angular? Below is my current .ts code, but I am open to any additional suggestions. esri-map.component.html <!-- Map ...

unable to reset contact form functionality

I need to implement a Contact Us form on my website. The form should clear the text fields after submission and display a Thank You message. Below is the HTML code: <div class="form"> <div id="sendmessage">Your message has been sent. Thank yo ...

Tips on how to patiently wait until the database connection is established and all queries are successfully executed for every database specified in an array

A file containing JSON data with database details needs to execute a series of queries for each database connection. The map function is currently waiting for the database connection. Below is the start function function start() { console.log('func ...

What is the best method for establishing a many-to-many relationship between models in sequelize node.js?

I am looking to establish a many-to-many association in my Node.js application using Sequelize, as I am relatively new to the Sequelize ORM. Currently, I have a model called `user.js` and I wish to create a new model called `project` and establish a many- ...

Implementing the sorting feature in Angular JS to properly align sub sections with their correct parent sections

I'm facing an issue with the functionality of my sample code. Users can add sections and subsections within those sections, which are sortable using ui-sortable. However, after sorting the items, if I try to add a new sub-section to Section 2, it wron ...

What is the proper way to structure the ng-options syntax in AngularJS?

I received an array from a REST service and I am attempting to generate a dropdown menu based on that data. Check out the jsfiddle example here $scope.reasons = [{ "languageLanguageId": { "languageId": 1, "lastUpdate": "2015-05-08T11:14:00+03:00" ...

Transitioning from a traditional CURL method to utilizing AJAX and XMLHttp

I'm currently facing a challenge converting the curl code from an API named TextRazor to AJAX XMLHttp due to limitations on the platform I am working with. Despite trying various solutions shared by the community, I have been unsuccessful in retrievin ...

What is the process for retrieving the user's information following successful social media login?

I have implemented Firebase for authentication in plain JavaScript, without using any frameworks like AngularJS or Angular2. When a user signs up successfully with Google or Facebook, I want to display their name, email, and profile picture. firebase.auth ...