[clang-tools-extra] [clang-doc] Add button a toggle for light/dark theme (PR #181587)
Erick Velez via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 6 12:13:42 PST 2026
https://github.com/evelez7 updated https://github.com/llvm/llvm-project/pull/181587
>From 6c7c656dc2d84f02c74b0821c7816c9fe987f14b Mon Sep 17 00:00:00 2001
From: Erick Velez <erickvelez7 at gmail.com>
Date: Fri, 13 Feb 2026 19:14:54 -0800
Subject: [PATCH 1/4] [clang-doc] Add button a toggle for light/dark theme
ALso fixes a typo that caused some overflow issues even when there was
no content to cause an overflow.
---
.../clang-doc/assets/clang-doc-mustache.css | 10 +++-
.../clang-doc/assets/head-template.mustache | 5 +-
.../clang-doc/assets/navbar-template.mustache | 51 +++++++++++++++++++
3 files changed, 63 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
index 3727981efddc5..0f8f902438e05 100644
--- a/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
+++ b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
@@ -1,7 +1,7 @@
/* css for clang-doc mustache backend */
@import "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap";
-*,*::before *::after {
+*,*::before, *::after {
box-sizing:border-box
}
* {
@@ -88,6 +88,7 @@ html, body {
margin: 0;
padding: 0;
width: 100%;
+ overflow-x: scroll;
}
.container {
@@ -179,6 +180,13 @@ header {
justify-self:center
}
+#theme-toggle {
+ grid-column: 3;
+ justify-self: end;
+ color: var(--text1);
+ border: none;
+}
+
@media(max-width:768px) {
.navbar__menu {
flex-direction:column;
diff --git a/clang-tools-extra/clang-doc/assets/head-template.mustache b/clang-tools-extra/clang-doc/assets/head-template.mustache
index 2ee4823fb77c1..67fcfc565f2da 100644
--- a/clang-tools-extra/clang-doc/assets/head-template.mustache
+++ b/clang-tools-extra/clang-doc/assets/head-template.mustache
@@ -8,8 +8,9 @@
<script src="{{.}}"></script>
{{/Scripts}}
{{! Highlight.js dependency for syntax highlighting }}
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" media="(prefers-color-scheme: light)">
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/dark.min.css" media="(prefers-color-scheme: dark)">
+ <link id="hljs-light-theme" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" />
+ <link id="hljs-dark-theme" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/dark.min.css" />
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0&icon_names=routine" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/cpp.min.js"></script>
</head>
diff --git a/clang-tools-extra/clang-doc/assets/navbar-template.mustache b/clang-tools-extra/clang-doc/assets/navbar-template.mustache
index 666a4c3e93739..810fccf919942 100644
--- a/clang-tools-extra/clang-doc/assets/navbar-template.mustache
+++ b/clang-tools-extra/clang-doc/assets/navbar-template.mustache
@@ -12,6 +12,7 @@
</li>
</ul>
</div>
+ <button id="theme-toggle"><span class="material-symbols-rounded">routine</span></button>
</div>
{{#HasContexts}}
<div class="navbar-breadcrumb-container">
@@ -21,3 +22,53 @@
</div>
{{/HasContexts}}
</nav>
+<script>
+ const root = document.documentElement;
+ const toggle = document.getElementById("theme-toggle");
+ const hlLight = document.getElementById("hljs-light-theme");
+ const hlDark = document.getElementById("hljs-dark-theme");
+
+ function changeHighlightJS(theme) {
+ if (theme === "dark") {
+ hlDark.disabled = false;
+ hlLight.disabled = true;
+ } else {
+ hlDark.disabled = true;
+ hlLight.disabled = false;
+ }
+ }
+
+ // Listen to system theme changes.
+ // If the user manually toggles the theme, the theme wont change according
+ // to system changes.
+ const themeQuery = window.matchMedia("(prefers-color-scheme: dark)");
+ themeQuery.addEventListener("change", (event) => {
+ if (savedTheme === null) {
+ return;
+ } else if (event.matches) {
+ changeHighlightJS("dark");
+ } else {
+ changeHighlightJS("light");
+ }
+ });
+
+ toggle.onclick = () => {
+ const currentTheme = root.getAttribute("color-scheme");
+ const next = currentTheme === "dark" ? "light" : "dark";
+ changeHighlightJS(next);
+ root.setAttribute("color-scheme", next);
+ localStorage.setItem("theme", next);
+ };
+
+ document.addEventListener("DOMContentLoaded", () => {
+ const savedTheme = localStorage.getItem("theme");
+ const currentTheme = root.getAttribute("color-scheme");
+ if (savedTheme !== null) {
+ root.setAttribute("color-scheme", savedTheme);
+ changeHighlightJS(savedTheme);
+ } else {
+ root.setAttribute("color-scheme", currentTheme);
+ changeHighlightJS(currentTheme);
+ }
+ });
+</script>
>From 58d40dacd5817a03abf2142780fecb0993dfd734 Mon Sep 17 00:00:00 2001
From: Erick Velez <erickvelez7 at gmail.com>
Date: Sun, 15 Feb 2026 22:36:11 -0800
Subject: [PATCH 2/4] update dark light toggle
---
.../clang-doc/assets/clang-doc-mustache.css | 2 +-
.../clang-doc/assets/head-template.mustache | 45 +++++++++++++++++++
.../clang-doc/assets/navbar-template.mustache | 45 +------------------
3 files changed, 48 insertions(+), 44 deletions(-)
diff --git a/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
index 0f8f902438e05..7402d66628ebe 100644
--- a/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
+++ b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
@@ -180,7 +180,7 @@ header {
justify-self:center
}
-#theme-toggle {
+#themeToggle {
grid-column: 3;
justify-self: end;
color: var(--text1);
diff --git a/clang-tools-extra/clang-doc/assets/head-template.mustache b/clang-tools-extra/clang-doc/assets/head-template.mustache
index 67fcfc565f2da..d1aba0ada335e 100644
--- a/clang-tools-extra/clang-doc/assets/head-template.mustache
+++ b/clang-tools-extra/clang-doc/assets/head-template.mustache
@@ -10,6 +10,51 @@
{{! Highlight.js dependency for syntax highlighting }}
<link id="hljs-light-theme" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" />
<link id="hljs-dark-theme" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/dark.min.css" />
+ <script>
+ const root = document.documentElement;
+ const toggle = document.getElementById("theme-toggle");
+ const hlLight = document.getElementById("hljs-light-theme");
+ const hlDark = document.getElementById("hljs-dark-theme");
+
+ function changeHighlightJS(theme) {
+ if (theme === "dark") {
+ hlDark.disabled = false;
+ hlLight.disabled = true;
+ } else {
+ hlDark.disabled = true;
+ hlLight.disabled = false;
+ }
+ }
+
+ const savedTheme = localStorage.getItem("theme");
+ const themeQuery = window.matchMedia("(prefers-color-scheme: dark)");
+ if (savedTheme !== null) {
+ root.setAttribute("color-scheme", savedTheme);
+ changeHighlightJS(savedTheme);
+ } else {
+ let initialTheme;
+ if (themeQuery.matches) {
+ initialTheme = "dark";
+ } else {
+ initialTheme = "light";
+ }
+ root.setAttribute("color-scheme", initialTheme);
+ changeHighlightJS(initialTheme);
+ }
+
+ // Listen to system theme changes.
+ // If the user manually toggles the theme, the theme wont change according
+ // to system changes.
+ themeQuery.addEventListener("change", (event) => {
+ if (savedTheme === null) {
+ return;
+ } else if (event.matches) {
+ changeHighlightJS("dark");
+ } else {
+ changeHighlightJS("light");
+ }
+ });
+ </script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0&icon_names=routine" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/cpp.min.js"></script>
diff --git a/clang-tools-extra/clang-doc/assets/navbar-template.mustache b/clang-tools-extra/clang-doc/assets/navbar-template.mustache
index 810fccf919942..f8182f7afddb0 100644
--- a/clang-tools-extra/clang-doc/assets/navbar-template.mustache
+++ b/clang-tools-extra/clang-doc/assets/navbar-template.mustache
@@ -12,7 +12,7 @@
</li>
</ul>
</div>
- <button id="theme-toggle"><span class="material-symbols-rounded">routine</span></button>
+ <button id="themeToggle"><span class="material-symbols-rounded">routine</span></button>
</div>
{{#HasContexts}}
<div class="navbar-breadcrumb-container">
@@ -23,52 +23,11 @@
{{/HasContexts}}
</nav>
<script>
- const root = document.documentElement;
- const toggle = document.getElementById("theme-toggle");
- const hlLight = document.getElementById("hljs-light-theme");
- const hlDark = document.getElementById("hljs-dark-theme");
-
- function changeHighlightJS(theme) {
- if (theme === "dark") {
- hlDark.disabled = false;
- hlLight.disabled = true;
- } else {
- hlDark.disabled = true;
- hlLight.disabled = false;
- }
- }
-
- // Listen to system theme changes.
- // If the user manually toggles the theme, the theme wont change according
- // to system changes.
- const themeQuery = window.matchMedia("(prefers-color-scheme: dark)");
- themeQuery.addEventListener("change", (event) => {
- if (savedTheme === null) {
- return;
- } else if (event.matches) {
- changeHighlightJS("dark");
- } else {
- changeHighlightJS("light");
- }
- });
-
- toggle.onclick = () => {
+ themeToggle.onclick = () => {
const currentTheme = root.getAttribute("color-scheme");
const next = currentTheme === "dark" ? "light" : "dark";
changeHighlightJS(next);
root.setAttribute("color-scheme", next);
localStorage.setItem("theme", next);
};
-
- document.addEventListener("DOMContentLoaded", () => {
- const savedTheme = localStorage.getItem("theme");
- const currentTheme = root.getAttribute("color-scheme");
- if (savedTheme !== null) {
- root.setAttribute("color-scheme", savedTheme);
- changeHighlightJS(savedTheme);
- } else {
- root.setAttribute("color-scheme", currentTheme);
- changeHighlightJS(currentTheme);
- }
- });
</script>
>From 25d055d0c89f47be8c7a85176b3aa276ff7e4ed1 Mon Sep 17 00:00:00 2001
From: Erick Velez <erickvelez7 at gmail.com>
Date: Thu, 5 Mar 2026 16:41:42 -0800
Subject: [PATCH 3/4] fix flashing
---
.../clang-doc/assets/head-template.mustache | 36 ++++++++-----------
1 file changed, 15 insertions(+), 21 deletions(-)
diff --git a/clang-tools-extra/clang-doc/assets/head-template.mustache b/clang-tools-extra/clang-doc/assets/head-template.mustache
index d1aba0ada335e..7a0095f0e947c 100644
--- a/clang-tools-extra/clang-doc/assets/head-template.mustache
+++ b/clang-tools-extra/clang-doc/assets/head-template.mustache
@@ -1,6 +1,15 @@
<head>
<meta charset="utf-8"/>
<title>{{Name}}</title>
+ <script data-cfasync="false">
+ (function() {
+ const root = document.documentElement;
+ const savedTheme = localStorage.getItem("theme");
+ const theme = savedTheme || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
+ root.setAttribute("color-scheme", theme);
+ window.__clangDocTheme = theme;
+ })();
+ </script>
{{#Stylesheets}}
<link rel="stylesheet" type="text/css" href="{{.}}"/>
{{/Stylesheets}}
@@ -12,7 +21,6 @@
<link id="hljs-dark-theme" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/dark.min.css" />
<script>
const root = document.documentElement;
- const toggle = document.getElementById("theme-toggle");
const hlLight = document.getElementById("hljs-light-theme");
const hlDark = document.getElementById("hljs-dark-theme");
@@ -26,33 +34,19 @@
}
}
- const savedTheme = localStorage.getItem("theme");
+ changeHighlightJS(window.__clangDocTheme);
const themeQuery = window.matchMedia("(prefers-color-scheme: dark)");
- if (savedTheme !== null) {
- root.setAttribute("color-scheme", savedTheme);
- changeHighlightJS(savedTheme);
- } else {
- let initialTheme;
- if (themeQuery.matches) {
- initialTheme = "dark";
- } else {
- initialTheme = "light";
- }
- root.setAttribute("color-scheme", initialTheme);
- changeHighlightJS(initialTheme);
- }
-
// Listen to system theme changes.
// If the user manually toggles the theme, the theme wont change according
// to system changes.
themeQuery.addEventListener("change", (event) => {
- if (savedTheme === null) {
+ if (localStorage.getItem("theme") !== null) {
return;
- } else if (event.matches) {
- changeHighlightJS("dark");
- } else {
- changeHighlightJS("light");
}
+
+ const theme = event.matches ? "dark" : "light";
+ root.setAttribute("color-scheme", theme);
+ changeHighlightJS(theme);
});
</script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0&icon_names=routine" />
>From 3dc09f523494281356b7c82b5773c83cd9a1eaaa Mon Sep 17 00:00:00 2001
From: Erick Velez <erickvelez7 at gmail.com>
Date: Fri, 6 Mar 2026 12:13:26 -0800
Subject: [PATCH 4/4] align tests
---
.../test/clang-doc/basic-project.mustache.test | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/test/clang-doc/basic-project.mustache.test b/clang-tools-extra/test/clang-doc/basic-project.mustache.test
index 200e763d28147..c94008f7bdf36 100644
--- a/clang-tools-extra/test/clang-doc/basic-project.mustache.test
+++ b/clang-tools-extra/test/clang-doc/basic-project.mustache.test
@@ -28,7 +28,8 @@ HTML-SHAPE: <a href="../index.html" class="navbar__link">Hom
HTML-SHAPE: <div class="navbar-breadcrumb-container">
HTML-SHAPE-NEXT: <a href="./index.html"><div class="navbar-breadcrumb-item">Global Namespace</div></a>
HTML-SHAPE: </nav>
-HTML-SHAPE-NEXT: </header>
+HTML-SHAPE-NEXT: <script>
+HTML-SHAPE: </header>
HTML-SHAPE-LABEL:<main>
HTML-SHAPE-NEXT: <div class="container">
HTML-SHAPE-NEXT: <div class="sidebar">
@@ -126,7 +127,8 @@ HTML-CALC: <a href="../index.html" class="navbar__link">Home
HTML-CALC: <div class="navbar-breadcrumb-container">
HTML-CALC-NEXT: <a href="./index.html"><div class="navbar-breadcrumb-item">Global Namespace</div></a>
HTML-CALC: </nav>
-HTML-CALC-NEXT: </header>
+HTML-CALC-NEXT: <script>
+HTML-CALC: </header>
HTML-CALC-LABEL:<main>
HTML-CALC-NEXT: <div class="container">
HTML-CALC-NEXT: <div class="sidebar">
@@ -331,7 +333,8 @@ HTML-RECTANGLE: <a href="../index.html" class="navbar__link"
HTML-RECTANGLE: <div class="navbar-breadcrumb-container">
HTML-RECTANGLE-NEXT: <a href="./index.html"><div class="navbar-breadcrumb-item">Global Namespace</div></a>
HTML-RECTANGLE: </nav>
-HTML-RECTANGLE-NEXT: </header>
+HTML-RECTANGLE-NEXT: <script>
+HTML-RECTANGLE: </header>
HTML-RECTANGLE-LABEL:<main>
HTML-RECTANGLE-NEXT: <div class="container">
HTML-RECTANGLE-NEXT: <div class="sidebar">
@@ -436,7 +439,8 @@ HTML-CIRCLE: <a href="../index.html" class="navbar__link">Ho
HTML-CIRCLE: <div class="navbar-breadcrumb-container">
HTML-CIRCLE-NEXT: <a href="./index.html"><div class="navbar-breadcrumb-item">Global Namespace</div></a>
HTML-CIRCLE: </nav>
-HTML-CIRCLE-NEXT: </header>
+HTML-CIRCLE-NEXT: <script>
+HTML-CIRCLE: </header>
HTML-CIRCLE-LABEL:<main>
HTML-CIRCLE-NEXT: <div class="container">
HTML-CIRCLE-NEXT: <div class="sidebar">
More information about the cfe-commits
mailing list