Root cause: topbar, dropdowns, toast, approval card, tooltips, main area, inputs, and hover states all used hardcoded rgba(22,33,62), #1a2535, etc. These only looked correct on the Dark theme — all other themes showed jarring dark-navy elements on non-navy backgrounds. New CSS variables added to every theme block: - --surface: dropdowns, popups, toast, approval card - --topbar-bg: topbar background - --main-bg: main chat area background - --input-bg: subtle input/button backgrounds - --hover-bg: hover state backgrounds - --focus-ring / --focus-glow: focus border and box-shadow Light theme now has proper light-colored surfaces, inputs, and hover states instead of invisible white-on-white. THEMES.md updated with all new variables documented. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5.2 KiB
Hermes Web UI — Themes
Hermes Web UI supports pluggable color themes. Five themes ship built-in, and you can create your own with pure CSS — no Python changes needed.
Switching Themes
Settings panel: Click the gear icon, select a theme from the dropdown. The preview is instant — the UI updates as you click through options.
Slash command: Type /theme dark or /theme light in the composer.
Themes persist across page reloads and server restarts (stored in
settings.json server-side, with localStorage for flicker-free loading).
Built-in Themes
| Theme | Description |
|---|---|
| Dark (default) | Deep navy/indigo with muted blue accents. Easy on the eyes for long sessions. |
| Light | Warm off-white with dark text. High contrast for bright environments. |
| Slate | Warm charcoal, lighter than Dark. Easier on the eyes for extended use. |
| Solarized Dark | Ethan Schoonover's classic dark palette. Teal background, warm accents. |
| Monokai | Warm dark theme inspired by the Monokai editor scheme. Green/pink accents. |
| Nord | Arctic blue-gray palette from the Nord color system. Calm and minimal. |
Creating a Custom Theme
A theme is a CSS block that overrides the color variables. Add it to
static/style.css (or a separate file that you link after the main stylesheet).
Step 1: Define your theme block
Every color in the UI comes from these CSS variables:
:root[data-theme="your-theme-name"] {
/* Core palette */
--bg: #1a1a2e; /* Main background */
--sidebar: #16213e; /* Sidebar background */
--border: rgba(255,255,255,0.08); /* Subtle borders */
--border2: rgba(255,255,255,0.14); /* Stronger borders */
--text: #e8e8f0; /* Primary text color */
--muted: #8888aa; /* Secondary/muted text */
--accent: #e94560; /* Accent color (errors, warnings, delete) */
--blue: #7cb9ff; /* Primary action color (links, active states) */
--gold: #c9a84c; /* Secondary accent (pinned items, gold highlights) */
--code-bg: #0d1117; /* Code block background */
/* Surface and chrome (optional — inherit from core palette if omitted) */
--surface: #1a2535; /* Dropdowns, popups, toast, approval card */
--topbar-bg: rgba(22,33,62,.98); /* Topbar background */
--main-bg: rgba(26,26,46,0.5); /* Main chat area background */
--input-bg: rgba(255,255,255,.04); /* Input/button subtle backgrounds */
--hover-bg: rgba(255,255,255,.06); /* Hover state backgrounds */
--focus-ring: rgba(124,185,255,.35); /* Focus border color */
--focus-glow: rgba(124,185,255,.08); /* Focus box-shadow glow */
}
The core palette (first 10 variables) controls 90% of the UI. The surface/chrome variables are optional — if omitted, they fall back to defaults that work for dark themes. Light themes should override all of them.
Step 2: Add it to the theme picker (optional)
To make your theme appear in the Settings dropdown, add an <option> to the
theme <select> in static/index.html:
<option value="your-theme-name">Your Theme Name</option>
And update the /theme command's valid theme list in static/commands.js.
Step 3: Test it
Switch to your theme via /theme your-theme-name or the Settings panel.
Check these areas:
- Sidebar session list (hover states, active state, project borders)
- Message bubbles (user vs assistant styling)
- Code blocks (background contrast, copy button visibility)
- Tool cards (running indicator, expand/collapse)
- Settings panel and login page
- Mobile layout (hamburger sidebar, bottom nav)
Tips
- Light themes need additional scrollbar overrides to avoid dark scrollbars on a light background. See the built-in light theme for the pattern.
- The logo gradient uses
--accentautomatically, so it adapts to your theme without extra work. - Prism.js syntax highlighting uses its own CDN stylesheet (Tomorrow theme). It works well on dark themes; on light themes the contrast is acceptable but not perfect. Custom Prism theme support is planned for a future update.
- No server changes needed. The
themesetting insettings.jsonaccepts any string — your custom theme name will persist without code changes.
How Themes Work Internally
- Each theme is a
:root[data-theme="name"]CSS block that overrides variables. - Switching themes sets
document.documentElement.dataset.theme = namein JS. - A tiny inline
<script>in<head>readslocalStoragebefore the stylesheet loads — this prevents a flash of the wrong theme on page load. - The theme preference is saved server-side via
POST /api/settingsand loaded on boot viaGET /api/settings. - The
/themecommand and Settings dropdown both update the DOM, localStorage, and server settings simultaneously.
Contributing a Theme
To contribute a new built-in theme:
- Add your
:root[data-theme="name"]block tostatic/style.css - Add the
<option>to the Settings panel instatic/index.html - Add the theme name to the valid list in
cmdTheme()instatic/commands.js - Test on desktop and mobile
- Open a PR — themes are pure CSS additions with no backend changes needed