đź’‰ Code Injection Paste in: Footer

Custom Dark Mode Toggle Button

Add a stylish dark mode toggle button to your Ghost site header with smooth transitions and saved preferences.

Custom Dark Mode Toggle Button

Add a toggle button that lets visitors switch between light and dark modes, with their preference saved in local storage for future visits. Works with any Ghost theme that supports the .dark-mode CSS class.

The Code

Paste this into your Ghost site’s Settings → Code injection → Site footer:

<script>
(function() {
var toggle = document.createElement('button');
toggle.id = 'theme-toggle';
toggle.textContent = '\u{1F319}';
toggle.setAttribute('aria-label', 'Toggle dark mode');
toggle.style.cssText =
'position:fixed;bottom:20px;right:20px;width:48px;height:48px;' +
'border-radius:50%;border:none;background:var(--ghost-accent-color,#3b82f6);' +
'color:white;font-size:20px;cursor:pointer;' +
'box-shadow:0 4px 12px rgba(0,0,0,0.15);' +
'transition:transform 0.2s,box-shadow 0.2s;z-index:9999;';
toggle.addEventListener('mouseenter', function() {
toggle.style.transform = 'scale(1.1)';
toggle.style.boxShadow = '0 6px 16px rgba(0,0,0,0.2)';
});
toggle.addEventListener('mouseleave', function() {
toggle.style.transform = 'scale(1)';
toggle.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
});
var isDark = localStorage.getItem('theme') === 'dark' ||
(!localStorage.getItem('theme') &&
window.matchMedia('(prefers-color-scheme: dark)').matches);
if (isDark) {
document.documentElement.classList.add('dark-mode');
toggle.textContent = '\u{2600}\u{FE0F}';
}
toggle.addEventListener('click', function() {
var isDarkNow = document.documentElement.classList.toggle('dark-mode');
toggle.textContent = isDarkNow ? '\u{2600}\u{FE0F}' : '\u{1F319}';
localStorage.setItem('theme', isDarkNow ? 'dark' : 'light');
});
document.body.appendChild(toggle);
})();
</script>

How to Install

  1. In Ghost Admin, go to Settings → Code injection
  2. Paste the code above into the Site footer section
  3. Click Save
  4. Visit your site — the toggle button appears in the bottom-right corner

Preventing the Flash of Light (FOUC)

Because this code runs in the Site footer, there’s a brief moment on page load where the page renders in light mode before the script applies the dark class. This “flash of unstyled content” (FOUC) is noticeable for returning dark-mode users.

To eliminate the flash, add this separate snippet to Settings → Code injection → Site header (which runs before the page renders):

<script>
(function() {
var theme = localStorage.getItem('theme');
if (theme === 'dark' || (!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark-mode');
}
})();
</script>

This tiny script reads the saved preference and applies the dark class immediately — before any content paints. The footer script then handles the toggle button and click events as normal.

How It Works

The script creates a floating button element positioned at the bottom-right of the viewport. On click, it toggles the .dark-mode class on the <html> element and saves the preference to localStorage.

On page load, the script checks for a saved preference. If none exists, it respects the user’s operating system preference via prefers-color-scheme. This means first-time visitors who use dark mode on their device automatically see the dark theme.

The button uses textContent instead of innerHTML for the emoji icons — this avoids potential XSS vectors and is the safer DOM manipulation method.

Customization

Change button position: Modify the bottom and right values in the style.cssText string. For example, bottom:80px moves it up (useful if it overlaps Ghost Portal).

Change button color: Replace var(--ghost-accent-color,#3b82f6) with any hex color. The var(--ghost-accent-color) automatically matches your theme’s accent color.

Use icon fonts instead of emoji: Replace toggle.textContent = '\u{1F319}' with an icon element. For Font Awesome: create a <i> element with the appropriate class and append it to the button instead.