Skip to main content

Available Themes

Markdown-OS includes 6 built-in themes with automatic syntax highlighting and Mermaid coordination:
Clean, professional light theme with blue accents.
{
  id: "light",
  name: "Default Light",
  type: "light",
  dots: ["#f7f8fa", "#17233b", "#2563eb"],
  highlightTheme: "github",
  mermaidTheme: "default",
}
  • Background: #f7f8fa (light gray)
  • Text: #17233b (dark blue-gray)
  • Accent: #2563eb (blue)

Switching Themes

Theme Dropdown

Click the color dots in the top-right corner to open the theme selector:
<div id="theme-dropdown">
  <button id="theme-dropdown-toggle" aria-label="Select theme">
    <div id="theme-dots">
      <span class="dot" style="background: var(--bg)"></span>
      <span class="dot" style="background: var(--text)"></span>
      <span class="dot" style="background: var(--accent)"></span>
    </div>
  </button>
  <div id="theme-dropdown-menu" class="hidden">
    <!-- Theme options -->
  </div>
</div>
The dropdown shows:
  • Theme name (e.g., “Default Dark”)
  • Color preview dots (background, text, accent)
  • Active theme indicator (checkmark)

Keyboard Navigation

The theme dropdown is fully keyboard accessible:
  • Enter or Space - Open/close dropdown
  • Arrow Up/Down - Navigate themes
  • Enter - Select highlighted theme
  • Escape - Close dropdown
function onDropdownMenuKeyDown(event) {
  if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
    event.preventDefault();
    navigateThemes(event.key === 'ArrowDown' ? 1 : -1);
  } else if (event.key === 'Enter') {
    event.preventDefault();
    selectHighlightedTheme();
  } else if (event.key === 'Escape') {
    closeDropdown();
  }
}

Theme Persistence

Selected themes are saved to localStorage:
const THEME_KEY = "markdown-os-theme";

function persistTheme(themeId) {
  try {
    window.localStorage.setItem(THEME_KEY, themeId);
  } catch (error) {
    console.warn('Failed to save theme preference:', error);
  }
}

function readSavedTheme() {
  try {
    const storedTheme = window.localStorage.getItem(THEME_KEY);
    if (themeById.has(storedTheme)) {
      return storedTheme;
    }
  } catch (error) {
    return null;
  }
}
Your theme preference persists across:
  • Browser restarts
  • Different files and directories
  • Multiple editor sessions
If localStorage is unavailable (private browsing, storage quota exceeded), themes fall back to system preference.

System Theme Detection

On first launch, the editor detects your operating system’s color scheme:
function detectSystemTheme() {
  const systemQuery = window.matchMedia("(prefers-color-scheme: dark)");
  return systemQuery.matches ? "dark" : "light";
}
This uses the prefers-color-scheme CSS media query to match your system settings:
  • macOS: System Preferences → General → Appearance
  • Windows: Settings → Personalization → Colors
  • Linux: Varies by desktop environment
Changing your system theme while the editor is open triggers automatic theme updates if you haven’t manually selected a theme.

Theme Architecture

CSS Custom Properties

Themes are implemented with CSS variables in themes.css:
[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0f172a;
  --panel-bg: #1e293b;
  --border: #334155;
  --text: #e2e8f0;
  --text-muted: #94a3b8;
  --accent: #60a5fa;
  --accent-soft: #1e3a5f;
  --success: #14b8a6;
  --danger: #f87171;
  --warning: #fbbf24;
  --shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
  
  --editor-bg: #1e293b;
  --editor-text: #e2e8f0;
  --code-block-bg: #0f172a;
  --modal-bg: #1e293b;
  /* ...many more variables */
}
All UI components reference these variables:
.editor {
  background: var(--editor-bg);
  color: var(--editor-text);
}

.button-primary {
  background: var(--accent);
  color: white;
}

.code-block {
  background: var(--code-block-bg);
  border: 1px solid var(--border);
}

Theme Application

When you select a theme, the ThemeManager class:
  1. Sets data attribute on <html> element:
    document.documentElement.setAttribute('data-theme', themeId);
    
  2. Updates highlight.js stylesheet:
    const HIGHLIGHT_THEME_BASE = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles";
    highlightTheme.href = `${HIGHLIGHT_THEME_BASE}/${theme.highlightTheme}.min.css`;
    
  3. Configures Mermaid theme:
    mermaid.initialize({
      theme: theme.mermaidTheme,
      startOnLoad: false,
    });
    
  4. Emits theme change event:
    window.dispatchEvent(new CustomEvent('themeChanged', {
      detail: { themeId, theme }
    }));
    
Changing themes re-renders all Mermaid diagrams to match the new color scheme.

Syntax Highlighting

Highlight.js Integration

Each theme specifies a highlight.js stylesheet:
ThemeHighlight.js Style
Default Lightgithub
Default Darkgithub-dark
Draculabase16/dracula
Nord Lightgithub
Nord Darknord
Lofigrayscale
The stylesheet is dynamically loaded:
const highlightTheme = document.getElementById('highlight-theme');
highlightTheme.href = `${HIGHLIGHT_THEME_BASE}/${theme.highlightTheme}.min.css`;
Code blocks are highlighted using:
hljs.configure({
  languages: ['javascript', 'python', 'bash', 'json', 'html', 'css', 'markdown']
});

document.querySelectorAll('pre code').forEach((block) => {
  hljs.highlightElement(block);
});

Mermaid Theme Coordination

Mermaid diagrams use theme-coordinated color schemes:
const mermaidThemeMap = {
  'light': 'default',
  'dark': 'dark',
  'dracula': 'dark',
  'nord-light': 'neutral',
  'nord-dark': 'dark',
  'lofi': 'neutral',
};

mermaid.initialize({
  theme: mermaidThemeMap[currentTheme],
  themeVariables: {
    primaryColor: getComputedStyle(document.documentElement)
      .getPropertyValue('--accent').trim(),
  },
});
This ensures diagrams match your selected theme automatically.

Creating Custom Themes

While Markdown-OS doesn’t currently support user-defined themes in the UI, you can add custom themes by modifying the source:
1

Define theme object

Add your theme to the THEMES array in static/js/theme.js:
{
  id: "custom",
  name: "My Custom Theme",
  type: "dark", // or "light"
  dots: ["#bg-color", "#text-color", "#accent-color"],
  highlightTheme: "github-dark",
  mermaidTheme: "dark",
}
2

Add CSS variables

Define your theme’s CSS custom properties in static/css/themes.css:
[data-theme="custom"] {
  color-scheme: dark;
  --bg: #1a1a1a;
  --panel-bg: #2a2a2a;
  --border: #3a3a3a;
  --text: #e0e0e0;
  --text-muted: #a0a0a0;
  --accent: #ff6b6b;
  /* ...define all required variables */
}
3

Test and refine

Reload the editor and select your custom theme from the dropdown. Test all UI components to ensure consistent appearance.
Copy an existing theme definition and modify colors incrementally. The dots array should contain representative colors for the preview in the theme dropdown.

Theme Variables Reference

Common variables used across themes:

Core Colors

--bg                    /* Main background */
--panel-bg              /* Sidebar and panel backgrounds */
--border                /* Border color for dividers */
--text                  /* Primary text color */
--text-muted            /* Secondary/dimmed text */
--accent                /* Brand/highlight color */
--accent-soft           /* Subtle accent background */

Semantic Colors

--success               /* Success states (green) */
--danger                /* Error/delete actions (red) */
--warning               /* Warning states (yellow/orange) */
--shadow                /* Drop shadow definition */

Component-Specific

--editor-bg             /* Editor content area background */
--editor-text           /* Editor text color */
--code-block-bg         /* Code block background */
--code-header-bg        /* Code block header bar */
--modal-bg              /* Dialog/modal background */
--modal-overlay         /* Modal backdrop overlay */
--table-border          /* Table cell borders */
--table-header-bg       /* Table header background */

File Tree & Tabs

--file-tab-bg           /* Tab background */
--file-tab-hover-bg     /* Tab hover state */
--file-tab-active-text  /* Active tab text */
--file-tab-dirty        /* Unsaved changes indicator */
--file-tab-border       /* Tab border color */

Accessibility Considerations

Color Contrast

All themes meet WCAG AA contrast requirements for normal text (4.5:1):
// Example contrast ratios
// Default Light: #17233b on #f7f8fa = 11.2:1
// Default Dark: #e2e8f0 on #0f172a = 13.8:1
// Dracula: #f8f8f2 on #282a36 = 12.5:1

Reduced Motion

Theme transitions respect the prefers-reduced-motion setting:
@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

Focus Indicators

Focus rings use theme-aware accent colors:
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

Performance

Theme Switching Speed

Theme changes are near-instantaneous because:
  • CSS variables update synchronously
  • No page reload required
  • Highlight.js stylesheet loads from CDN cache
  • Mermaid diagrams re-render asynchronously

Initial Load

The editor applies the saved theme before first paint to prevent flashing:
init() {
  const savedTheme = this.readSavedTheme();
  const initialThemeId = savedTheme ?? this.detectSystemTheme();
  this.applyTheme(initialThemeId, { emitThemeEvent: false });
  
  window.setTimeout(() => {
    document.documentElement.classList.remove('loading');
  }, 100);
}
html.loading * {
  transition: none !important;
}
This prevents the brief flash of default styles during page load.

Build docs developers (and LLMs) love