From 8a4f771aa58126005a5342b44beae8354091d133 Mon Sep 17 00:00:00 2001
From: Axel Bocciarelli
Date: Mon, 21 Sep 2026 11:25:01 +0200
Subject: [PATCH] Add color scheme configuration and follow VS Code's theme by
default
---
CHANGELOG.md | 3 +++
README.md | 10 ++++++++++
extension/H5WebViewer.ts | 6 +++++-
package.json | 24 +++++++++++++++++++++++-
src/App.tsx | 9 ++++++++-
src/StandaloneViewer.tsx | 5 +++--
src/Viewer.tsx | 5 +++--
src/index.css | 27 +++++++++++++++++++++++++++
8 files changed, 82 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ee783d1..7c32ace 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@
- 🧩 Open `.nde` files in H5Web by default
- ✨ Improve error display when a file is deleted
- ✨ Reload a file automatically when it is recreated
+- ✨ Follow VS Code's theme by default instead of the operating system's
+- ⚙️ Add `h5web.colorScheme` setting to control the color scheme behaviour
+ (requires reopening H5Web editors)
- 🐛 Release the previous contents of the file from memory when it is reloaded
- 🐛 Stop leaving a copy of every file opened from the explorer in VS Code's
webview cache, where copies accumulated with no size limit and were never
diff --git a/README.md b/README.md
index 4ae6f4f..0ccebcf 100644
--- a/README.md
+++ b/README.md
@@ -86,3 +86,13 @@ This is an issue from VSCode `snap` package that
[forces the use of `XWayland/X11` instead of `Wayland`](https://github.com/microsoft/vscode/issues/207033).
Since it can not be worked around, our advice is use another VSCode installation
instead (e.g. via `apt`).
+
+## Configuration
+
+### `h5web.colorScheme`
+
+Specifies whether to use a light or dark color scheme. By default, H5Web follows
+VS Code's theme.
+
+> After changing this setting, please reopen your H5Web editors for the new
+> color scheme to take effect.
diff --git a/extension/H5WebViewer.ts b/extension/H5WebViewer.ts
index 8cc7350..87693cc 100644
--- a/extension/H5WebViewer.ts
+++ b/extension/H5WebViewer.ts
@@ -143,6 +143,10 @@ export default class H5WebViewer implements CustomReadonlyEditorProvider {
'worker-src blob:', // for H5WasmLocalFileProvider's inline worker
];
+ const colorScheme = workspace
+ .getConfiguration('h5web')
+ .get('colorScheme', 'vscode');
+
return `
@@ -158,7 +162,7 @@ export default class H5WebViewer implements CustomReadonlyEditorProvider {
-
+
`;
diff --git a/package.json b/package.json
index ff75f67..e452108 100644
--- a/package.json
+++ b/package.json
@@ -51,7 +51,29 @@
],
"priority": "option"
}
- ]
+ ],
+ "configuration": {
+ "title": "H5Web",
+ "properties": {
+ "h5web.colorScheme": {
+ "description": "Specifies whether to use a light or dark color scheme. By default, follow VS Code's theme. Alternatively, follow the operating system's scheme or force a specific scheme.",
+ "type": "string",
+ "default": "vscode",
+ "enum": [
+ "vscode",
+ "system",
+ "light",
+ "dark"
+ ],
+ "enumDescriptions": [
+ "Follow VS Code's theme",
+ "Follow the system's color scheme",
+ "Use a light color scheme",
+ "Use a dark color scheme"
+ ]
+ }
+ }
+ }
},
"main": "./out/main.js",
"scripts": {
diff --git a/src/App.tsx b/src/App.tsx
index d2d8f69..b5573e4 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -36,9 +36,16 @@ function App() {
return
File does not exist
;
}
+ /* Configured color scheme is passed to webview via `data-color-scheme` attribute.
+ * If "system", let H5Web's default behaviour kick in (i.e. `prefer-color-scheme: dark`).
+ * Otherwise, take over control of the color scheme with CSS. */
+ const { colorScheme } = document.body.dataset;
+ const disableDarkMode = colorScheme !== 'system';
+
if (fileInfo.size >= MAX_SIZE_IN_BYTES) {
return (
File is too large to be opened from the explorer (max 2 GB). Please
@@ -58,7 +65,7 @@ function App() {
}}
>
Loading...
}>
-
+
);
diff --git a/src/StandaloneViewer.tsx b/src/StandaloneViewer.tsx
index a44a6f6..481c9f4 100644
--- a/src/StandaloneViewer.tsx
+++ b/src/StandaloneViewer.tsx
@@ -5,11 +5,12 @@ import { type ReactNode, useState } from 'react';
import { getExportURL, getPlugin } from './utils';
interface Props {
+ disableDarkMode: boolean;
customMessage?: ReactNode;
}
function StandaloneViewer(props: Props) {
- const { customMessage } = props;
+ const { disableDarkMode, customMessage } = props;
const [fallbackFile, setFallbackFile] = useState();
if (!fallbackFile) {
@@ -31,7 +32,7 @@ function StandaloneViewer(props: Props) {
getExportURL={getExportURL}
getPlugin={getPlugin}
>
-
+
);
}
diff --git a/src/Viewer.tsx b/src/Viewer.tsx
index 4d3d276..f5fa652 100644
--- a/src/Viewer.tsx
+++ b/src/Viewer.tsx
@@ -8,10 +8,11 @@ import WidthGuard from './WidthGuard.js';
interface Props {
fileInfo: FileInfo;
+ disableDarkMode: boolean;
}
function Viewer(props: Props) {
- const { fileInfo } = props;
+ const { fileInfo, disableDarkMode } = props;
const buffer = suspend(async () => {
// Make a range request so that VS Code's webview service worker doesn't keep a copy of it
@@ -33,7 +34,7 @@ function Viewer(props: Props) {
getPlugin={getPlugin}
>
-
+
);
diff --git a/src/index.css b/src/index.css
index b868da3..cc60980 100644
--- a/src/index.css
+++ b/src/index.css
@@ -9,3 +9,30 @@
[data-fill-height] {
height: 100vh;
}
+
+[data-color-scheme='dark'] #root,
+[data-color-scheme='vscode'][data-vscode-theme-kind='vscode-dark'] #root {
+ filter: invert();
+
+ /* Set shadows to lighter colors so they remain dark once inverted */
+ --h5w-btnRaised--shadowColor: #f5f5f5;
+ --h5w-btnRaised-hover--shadowColor: #fff;
+ --h5w-domainSlider-track--shadowColor: #f5f5f5;
+ --h5w-domainSlider-dataTrack--shadowColor: #fff;
+
+ /* Change line colors for better contrast once inverted */
+ --h5w-line--color: deepskyblue;
+ --h5w-line--colorAux: orange, lightgreen, red, violet, gold;
+}
+
+[data-color-scheme='dark'] #root [data-keep-colors],
+[data-color-scheme='dark'] #root [data-keep-canvas-colors] canvas,
+[data-color-scheme='vscode'][data-vscode-theme-kind='vscode-dark']
+ #root
+ [data-keep-colors],
+[data-color-scheme='vscode'][data-vscode-theme-kind='vscode-dark']
+ #root
+ [data-keep-canvas-colors]
+ canvas {
+ filter: invert(); /* invert back to normal colors */
+}