Color modes
Learn about the default color modes (light and dark) in Halfmoon, and how to toggle between them.
Create amazing Typeform-like forms and pages just by writing Markdown!
How it works #
Halfmoon supports two different color modes: light and dark. Every single component has proper support for both modes, and a user can toggle between the different modes with ease (if you make that functionality available). You do not need to include any other additional CSS files.
Color modes can be applied using the data-bs-theme
attribute. Depending on the value of the attribute ("light"
or "dark"
), all the elements and components within the container with the attribute will be styled using the given color mode. This means that if you set the attribute on the root <html>
element, the color mode will be applied globally. Please note, if the data-bs-theme
attribute is missing, then light mode is applied as the default color mode.
Global usage #
Enable the built in dark color mode across your entire project by adding the data-bs-theme="dark"
attribute to the <html>
element. This will apply the dark color mode to all components and elements, other than those with a specific data-bs-theme
attribute applied. Building on the starter template:
HTML
<!doctype html>
<html lang="en" data-bs-theme="dark">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Starter template - Halfmoon</title>
<!-- Halfmoon CSS -->
<link href="https://cdn.jsdelivr.net/npm/halfmoon@2.0.2/css/halfmoon.min.css" rel="stylesheet" integrity="sha256-RjeFzczeuZHCyS+Gvz+kleETzBF/o84ZRHukze/yv6o=" crossorigin="anonymous">
</head>
<body>
<h1>Hello, world!</h1>
<!-- Option 1: Bootstrap JS bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha256-CDOy6cOibCWEdsRiZuaHf8dSGGJRYuBGC+mjoJimHGw=" crossorigin="anonymous"></script>
<!-- Option 2: Separate Popper and Bootstrap JS
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha256-whL0tQWoY1Ku1iskqPFvmZ+CHsvmRWx/PIoEvIeWh4I=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha256-3gQJhtmj7YnV1fmtbVcnAV6eI4ws0Tr48bVZCThtCGQ=" crossorigin="anonymous"></script>
-->
</body>
</html>
Local usage #
You can also set a local color mode by adding data-bs-theme="light"
or data-bs-theme="dark"
to any element or container. This would set the local color mode for that element and its children.
Warning
We generally do not recommend using local color modes because they can cause some unexpected issues, such as this known one (opens in new tab). Local color modes will also not work properly with the core themes. The only two exceptions where we encourage local color mode usage are the following:
In both cases, we have overridden the CSS to make sure they always work properly. Also these are two components where having dedicated light and dark variants can be very useful. For all other components, you will probably be better off sticking to a global color mode.
It should be noted, however, that if you are aware of the issues, and don't want to use our core themes, you can absolutely use local color modes without any issue.
JavaScript toggler #
To allow visitors or users to toggle color modes, you'll need to create a toggle element to control the data-bs-theme
attribute on the root element, <html>
. We've built a toggler in our documentation that initially defers to a user's current system color mode, but provides an option to override that and pick a specific color mode.
Here's a similar implementation in JavaScript taken from the official Bootstrap documentation (opens in new tab). It is suggested to include the JavaScript at the top of your page to reduce potential screen flickering during reloading of your site.
JavaScript
/*!
* 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);
});
});
});
})();
Help us grow
Our main goal is to make Halfmoon the go-to framework for building websites, dashboards and tools. If you believe in our mission, consider becoming a sponsor and help us grow.
You can email us directly if you have any queries. We are always happy to answer.
Subscribe for updates
We will notify you when the framework gets a substantial update. No spam ever.
Follow us on Twitter so that you can stay updated that way.