5.7 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. |
| Custom themes | Any string accepted by settings.json, POST /api/settings, and /theme if added to the picker/command list. Pure CSS variables only. |
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 (required for full polish) */
--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 */
/* Text / code styling (required since PR #102) */
--strong: #fff; /* strong/bold text */
--em: #c9c9e8; /* italic text */
--code-text: #f0c27f; /* inline code + code blocks accent text */
--code-inline-bg: rgba(0,0,0,.35); /* inline code chip background */
--pre-text: #e2e8f0; /* code block / approval text */
}
The core palette controls the overall mood. The surface/chrome and text/code styling variables are now part of the standard theme contract, not optional extras. If you want a built-in theme to look complete, define 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 scrollbar and selection overrides, plus the full
text/code set (
--strong,--em,--code-text,--code-inline-bg,--pre-text) or they will look broken. - 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