Skip to content

bkuz114/themePicker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Theme Picker

A lightweight, vanilla JavaScript utility for multi-theme management. Toggle between themes by applying a prefixed class to <html> — perfect for CSS variable‑based theming.

  • Zero dependencies – pure vanilla JS
  • Small footprint – ~5KB minified
  • Framework agnostic – works anywhere
  • Accessible – works with screen readers (demos include ARIA labels)
  • Persistent – saves user preference to localStorage or sessionStorage

How it works

You define themes in your CSS using a class prefix (e.g., .theme-ocean, .theme-sunset). ThemePicker applies the corresponding class to <html> based on user selection or stored preference.

/* Your CSS */
.theme-ocean {
  --bg: #0ea5e9;
  --text: #082f49;
}

.theme-sunset {
  --bg: #f97316;
  --text: #7c2d12;
}

Installation

Copy themePicker.js into your project.

cp themePicker.js your-project/

Usage

1. Create a ThemePicker instance

const picker = new ThemePicker({
  themes: {
    ocean: { name: 'Ocean' },
    sunset: { name: 'Sunset' }
  },
  defaultTheme: 'ocean',
  storageType: 'local',
  onThemeChange: (newTheme, oldTheme) => {
    console.log(`${oldTheme}${newTheme}`);
  }
});

2. Build your own UI

The library does not provide UI components. You build the interface that fits your project.

// Example: bind a button
document.querySelector('#ocean-btn').addEventListener('click', () => {
  picker.applyTheme('ocean');
});

// Example: bind a dropdown
themeSelect.addEventListener('change', (e) => {
  picker.applyTheme(e.target.value);
});

3. Define your themes in CSS

.theme-ocean {
  --bg: #0ea5e9;
  --text: #082f49;
}

.theme-sunset {
  --bg: #f97316;
  --text: #7c2d12;
}

body {
  background: var(--bg);
  color: var(--text);
}

Configuration

Option Type Default Description
themes object (required) Theme definitions. Each key must have a name property.
classNamePrefix string 'theme-' Prefix for CSS classes. Final class: ${prefix}${themeKey}
storageKey string 'selectedTheme' Key used in localStorage/sessionStorage
storageType string 'local' 'local', 'session', or 'none' (no persistence)
defaultTheme string first key in themes Fallback when no stored preference exists
onThemeChange function null Callback fired when theme changes. Receives (newTheme, oldTheme)

API

applyTheme(theme)

Applies a theme by key. Returns true if successful, false if theme not found.

picker.applyTheme('sunset');

getCurrentTheme()

Returns the currently active theme key.

const current = picker.getCurrentTheme(); // 'ocean'

resetToDefault()

Resets to the default theme (as defined in defaultTheme).

picker.resetToDefault();

destroy()

Cleans up event listeners. Reserved for future features (cross‑tab sync). Call if removing the instance in an SPA.

picker.destroy();

Storage Options

storageType Behavior
'local' Persists indefinitely across browser restarts
'session' Persists within a tab; clears when tab closes
'none' No persistence; resets to default on each load

Browser Support

Modern evergreen browsers (Chrome, Firefox, Safari, Edge). Requires:

  • classList
  • localStorage / sessionStorage
  • ES6 (can be polyfilled)

Preventing FOUC (Flash of Unstyled Content)

ThemePicker applies the saved theme (i.e. localStorage or sessionStorage if specified in constructor) immediately when initialized. To prevent a flash of the wrong theme:

If you use a single .js file for initialization and UI rendering:

Place the script in <head> with no defer/async, and wrap UI-building code in DOMContentLoaded:

<head>
  <script src="theme-picker.js"></script>
  <script>
    const picker = new ThemePicker({ ... });
    document.addEventListener('DOMContentLoaded', () => {
      // Build your UI here
    });
  </script>
</head>

See the /demos directory for working examples of this pattern.

If you split into two files (recommended for complex UIs):

  1. theme-init.js — initialize ThemePicker. Place in <head> (no defer/async).
  2. ui-widget.js — build your theme picking UI. Place before </body> or with defer.

Demos

The /demos directory contains complete, copy‑pasteable examples:

  • Dropdown – compact select menu
  • Button Grid – playful emoji buttons
  • Radio Group – native HTML radios, fully accessible
  • Segmented Control – iOS‑style pill control

Open static demos/index.html to browse all demos.

Accessibility

ThemePicker itself does not render UI, but the included demos demonstrate accessible patterns:

  • Semantic HTML (fieldset, legend, button, label)
  • ARIA labels on interactive elements
  • Keyboard navigation support

When building your own UI, ensure buttons and controls have appropriate aria-label or visible text.

Why a class instead of global functions?

The class design allows:

  • Multiple instances (if needed)
  • Per‑instance callbacks
  • Cleaner encapsulation
  • Easier testing

License

MIT

About

Lightweight, vanilla js theme picking utility

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors