Now.js Framework Documentation

Now.js Framework Documentation

ThemeManager

EN 28 Dec 2025 09:45

ThemeManager

Overview

ThemeManager is the theme management system in Now.js Framework. It supports:

  • Light/Dark mode switching
  • Auto-enhanced toggle buttons (data-component="theme")
  • Backend API integration (load CSS Variables from server)
  • Smooth transitions (Anti-FOUC)
  • System preference detection

Basic Usage

Initialization

await Now.init({
  theme: {
    enabled: true,
    defaultTheme: 'light',
    storageKey: 'app_theme',
    systemPreference: true
  }
});

Toggle Theme

ThemeManager.toggle();               // Switch light ↔ dark
await ThemeManager.setTheme('dark'); // Set specific theme
const theme = ThemeManager.getCurrentTheme();

Toggle Button

HTML

<!-- Auto-enhanced - no JS required -->
<button data-component="theme">🌓</button>

ThemeManager will auto-enhance the button:

  • ✅ Adds click handler
  • ✅ Syncs data-theme-state attribute
  • ✅ All buttons sync when theme changes

CSS for Toggle Button

/* Icon font setup */
[data-component="theme"]:before {
  font-family: 'icomoon' !important;
}

/* Show icon based on theme */
[data-component="theme"][data-theme-state="light"]:before {
  content: "\e929";  /* icon-night */
}

[data-component="theme"][data-theme-state="dark"]:before {
  content: "\e9d4";  /* icon-day */
}

Or use CSS classes:

[data-theme-state="light"] .icon-light { display: none; }
[data-theme-state="dark"] .icon-dark { display: none; }

Full Configuration

await Now.init({
  theme: {
    enabled: true,
    defaultTheme: 'light',
    storageKey: 'app_theme',
    systemPreference: true,

    // Smooth Transitions
    transition: {
      enabled: true,
      duration: 300,
      hideOnSwitch: true,
      readyClass: 'theme-ready',
      transitionClass: 'theme-transitioning'
    },

    // Backend API
    api: {
      enabled: false,
      configUrl: '/api/theme/config',
      timeout: 5000,
      cacheResponse: true
    }
  }
});

Backend API Integration

Load Config from API

await ThemeManager.loadFromAPI('/api/theme/config');

API Response Format

{
  "variables": {
    "--color-primary": "#6366f1",
    "--color-background": "#0f172a",
    "--hero-bg": "images/hero.jpg"
  }
}

Note: API does NOT control light/dark mode - user controls that

CSS Variables

Apply Variables

ThemeManager.applyVariables({
  '--color-primary': '#6366f1',
  '--color-background': '#0f172a',
  '--hero-bg': '/images/hero.jpg'  // Auto-wraps as url()
});

Security

  • Only CSS Custom Properties (--*) allowed
  • Dangerous patterns removed (javascript:, expression(), <script>)
  • URLs: local paths or same-origin absolute URLs allowed
  • External domains blocked by default
  • Extensions must be images (no SVG)

Smooth Transitions

Required CSS

body {
  opacity: 0;
  transition: opacity 0.3s ease;
}

body.theme-ready {
  opacity: 1;
}

body.theme-transitioning {
  opacity: 0;
}

How It Works

  1. body starts with opacity: 0
  2. ThemeManager loads theme
  3. Adds theme-ready class → fade in
  4. On switch → fade out → apply → fade in

API Reference

Method Description
toggle() Toggle theme
setTheme(theme) Set theme
getCurrentTheme() Get current theme
applyVariables(vars) Apply CSS Variables
clearVariables() Remove CSS Variables
getAppliedVariables() Get applied variables
loadFromAPI(url?) Load from API
refreshFromAPI() Reload (clear cache)
destroy() Full cleanup
reset() Reset state

Events

Event When Triggered
theme:initialized Init complete
theme:changed Theme changed
theme:ready Ready to display
theme:variables-applied Variables applied
theme:variables-cleared Variables cleared
theme:api-loaded API load success
theme:api-error API error
theme:destroyed Cleanup complete
theme:reset Reset complete
EventManager.on('theme:changed', ({ theme }) => {
  console.log('Changed to:', theme);
});

Cleanup

// Full cleanup (unmount app)
ThemeManager.destroy();

// Light reset (re-init)
ThemeManager.reset();
await ThemeManager.init({ ... });

Common Pitfalls

⚠️ 1. Enable Before Use

// ❌ Not enabled
ThemeManager.toggle();

// ✅ Enable first
await Now.init({ theme: { enabled: true } });
ThemeManager.toggle();

⚠️ 2. Use CSS Variables

/* ❌ Using fixed values */
body { background: white; }

/* ✅ Use variables */
body { background: var(--color-background); }

⚠️ 3. Use HTTP Protocol

// ❌ file:// protocol can't use API
// ✅ http://localhost/...