Theme Selection

This website has two independent theme systems: a Bootswatch theme picker for the page layout (navbar, cards, body text) and a syntax theme selector for code block highlighting. Both are persisted in localStorage.

Bootswatch page theme

Uses Bootswatch themes with Bootstrap 5.3's data-bs-theme attribute.

How it works

  • A theme dropdown in the navbar lets users switch between all 27 Bootswatch themes
  • Selection persisted under localStorage key bootswatch-theme
  • On first visit, defaults to Darkly (dark OS preference) or Flatly (light OS preference) via prefers-color-scheme
  • An inline <head> script applies the theme before first paint to prevent a flash

Theme classification

Dark (7) Light (20)
Cyborg, Darkly, Quartz, Slate, Solar, Superhero, Vapor Brite, Cerulean, Cosmo, Flatly, Journal, Litera, Lumen, Lux, Materia, Minty, Morph, Pulse, Sandstone, Simplex, Sketchy, Spacelab, United, Yeti, Zephyr

Syntax highlighting theme

An independent syntax dropdown in the navbar controls the highlight.js stylesheet. It is separate from the Bootswatch theme — users can mix any page theme with any code theme.

Modes

Mode Behaviour
Auto (default) Maps to github-dark-dimmed for dark Bootswatch themes, github for light. Follows the page theme.
Manual Any explicit selection overrides auto. Bootswatch theme changes no longer affect the code theme.

Persistence

  • Key: localStorage key hljs-theme
  • Absent or "auto" → follow Bootswatch dark/light
  • Any theme name → use that theme independently
┌──────────────────────────────────────┐
│ Auto (follow theme)                ✓ │
│ ─ ─ ─ ─ ─ ─                         │
│ Dark                                 │
│   Atom One Dark                      │
│   Monokai Sublime                    │
│   Nord                               │
│   Dracula                            │
│   Night Owl                          │
│   Tokyo Night Dark                   │
│ ─ ─ ─ ─ ─ ─                         │
│ Light                                │
│   Atom One Light                     │
│   GitHub                             │
│   VS                                 │
│   XCode                              │
│   Tokyo Night Light                  │
│   IntelliJ Light                     │
│ ─ ─ ─ ─ ─ ─                         │
│ Other (245)                          │
│   └─ (lazy-loaded on expand)         │
│ Hide                                 │
└──────────────────────────────────────┘

Other themes

245 additional themes (all non-base16 + all base16 variants) are embedded as a JS array (window.HLJS_OTHER) in the <head> script. The DOM is generated lazily on first click of "Show all" — avoids rendering 245 nodes on every page load.

Implementation

All logic lives in templates/base.html:

  1. <link id="hljs-css"> — dynamically swapped via JS; no static default
  2. Inline <head> script — defines window.HLJS_OTHER, setHljs(theme) function; applies stored choice synchronously
  3. Dropdown menu — curated items hardcoded in HTML; "Other" section generated client-side
  4. Body script — click handlers for both Bootswatch and syntax dropdowns; Bootswatch handler only updates hljs when in auto mode; syntax handler saves to localStorage and swaps the CSS link

Theme swap mechanism

Class names are identical across all highlight.js themes (.hljs, .hljs-keyword, etc.). Swapping the <link> href causes the browser to recalculate styles automatically — no need to re-run hljs.highlightAll().

Interaction with Bootswatch

When the user changes the Bootswatch theme: - If hljs is in Auto mode → hljs theme updates to match the new dark/light classification - If hljs is in manual mode → no change

CDN

Bootswatch: https://cdn.jsdelivr.net/npm/bootswatch@5.3.8/dist/{theme}/bootstrap.min.css
highlight.js: https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/{theme}.min.css