trueshade
Reactive icon

TrueShade

Stable version 1.5.1 (Compatible with OutSystems 11)
Uploaded
 on 9 Jun (yesterday)
 by 
5.0
 (9 ratings)
trueshade

TrueShade

Documentation
1.5.1

Overview


TrueShade is a lightweight, dependency-free JavaScript module that manages UI color schemes (dark / light) for web applications. It persists the user's preference in localStorage, applies it to the <html> element via the data-theme attribute, reacts instantly to system color-scheme changes, and keeps every open tab in sync. It supports three modes: system-default, dark, and light.

Heads up: TrueShade is the logic and synchronization layer only — it does not ship dark/light CSS. You write your styles against the <html data-theme="dark|light"> attribute that TrueShade sets for you.


Purpose

  • Manage UI themes — switch between dark and light based on user or system preference.
  • Persistence — store the preference in localStorage under a module- or app-specific key.
  • System integration — follow OS-level changes via prefers-color-scheme.
  • Cross-tab & cross-app sync — keep the theme aligned across tabs, and optionally across multiple front-ends that share the same AppName.
  • Event-driven — notify subscribers the moment the theme changes.


Key Features

  • AppName support — initialize with an optional AppName to share preferences across front-ends in the same portal.
  • Idempotent lifecycle — safe initialization and disposal, with no duplicate listeners.
  • System-default support — resolves system-default to the live OS preference and updates the instant it changes.
  • Reliable cross-tab sync — uses BroadcastChannel where available, with an automatic storage-event fallback so no tab is left out of sync.
  • Event subscription — OnChange delivers both the resolved theme and the raw preference, with an opt-in immediate fire.
  • Minimal footprint — no dependencies, strict-mode JavaScript.
  • Error resilience — degrades gracefully when localStorage or BroadcastChannel are unavailable (e.g. privacy modes).


Installation

Install TrueShade from the OutSystems Forge.


Usage

Initialization

There are two ways to initialize TrueShade:

  • Simpler setup (recommended) — add the TrueShade Block directly to your Layout Block; it handles initialization and disposal automatically.
  • Manual setup — run the Initialize client action in your Layout Block's On Ready event, and call Dispose in On Destroy.

Pass an optional AppName to Initialize when several modules should share one preference.


Getting the current theme

Effective theme (dark or light) — client action GetLayoutColorScheme.

Raw stored preference (system-default, dark, or light) — client action GetStoredLayoutColorScheme.


Setting a theme

Set and persist a new theme with the client action SetLayoutColorScheme (system-default, dark, or light). Invalid values are rejected and logged as a console error.


Subscribing to theme changes

The callback receives the effective theme and the raw preference. Pass { immediate: true } to also fire once with the current theme on subscribe:

const unsubscribe = TrueShade.Theme.OnChange((effective, raw) => {
  console.log('Effective:', effective, '| Stored:', raw);
}, { immediate: true });

// Later, to unsubscribe:
unsubscribe();

Preventing the theme flash (FOUC)

Because the theme is applied during initialization, the page can briefly paint the wrong theme on first load. To avoid this, add a synchronous snippet to your page <head>, before any stylesheet. Replace MyApp with the AppName you pass to Initialize:

<script>
  (function () {
    try {
      var raw = localStorage.getItem('MyApp$layout-theme') || 'system-default';
      var dark = raw === 'dark' ||
        (raw === 'system-default' && matchMedia('(prefers-color-scheme: dark)').matches);
      document.documentElement.dataset.theme = dark ? 'dark' : 'light';
    } catch (e) { document.documentElement.dataset.theme = 'light'; }
  })();
</script>

Use GetStorageKey() to confirm the exact key at runtime.

Clean up

Dispose of the module to remove event listeners (the stored preference is preserved):

TrueShade.Theme.Dispose();

API Reference


Initialize(appName?)

  • Purpose: initializes the theme system (idempotent).
  • Behavior: optionally accepts appName for a shared key; seeds localStorage with system-default if unset; applies the theme to <html data-theme>; wires OS and cross-tab listeners.
  • Returns: void


GetLayoutColorScheme()

  • Purpose: returns the effective theme.
  • Behavior: resolves system-default to the current OS preference.
  • Returns: 'dark' | 'light'


GetStoredLayoutColorScheme()

  • Purpose: returns the raw stored preference.
  • Behavior: ensures the preference is seeded, returning system-default if unset.
  • Returns: 'system-default' | 'dark' | 'light'


SetLayoutColorScheme(theme)

  • Purpose: sets and persists a new theme.
  • Parameters: theme — 'system-default' | 'dark' | 'light'
  • Behavior: validates the input (logs a console error if invalid); persists to localStorage, applies to <html data-theme>, and notifies local subscribers and other tabs.
  • Returns: void


OnChange(callback, options?)

  • Purpose: subscribes to theme change events.
  • Parameters:
    • callback: (effective, raw) => void — effective is 'dark'/'light', raw is the stored preference. One-argument callbacks are also supported.
    • options (optional): { immediate: true } fires the callback once with the current theme on subscribe.
  • Behavior: a throwing callback is reported via console.error without interrupting other subscribers.
  • Returns: () => void — unsubscribe function.


GetStorageKey()

  • Purpose: returns the resolved localStorage key for the active module.
  • Returns: string — e.g. myapp$layout-theme or $OS_example$layout-theme


Dispose()

  • Purpose: cleans up resources (idempotent).
  • Behavior: removes OS and cross-tab listeners, clears the internal listener list, and preserves the stored preference.
  • Returns: void


Internal Mechanics


Storage key

  • With an AppName: <AppName>$layout-theme (e.g. myapp$layout-theme).
  • Without one (derived): $OS_<moduleName>$layout-theme, where moduleName comes from the URL's first path segment (or first hostname label).
  • Example: https://example.com/app → $OS_app$layout-theme.


Theme modes

  • system-default — follows the OS prefers-color-scheme (dark or light).
  • dark — forces dark mode.
  • light — forces light mode.


Event handling

  • OS changes: listens to prefers-color-scheme via window.matchMedia; updates only when the preference is system-default.
  • Cross-tab & cross-app sync: broadcasts local changes over BroadcastChannel (with a storage-event fallback) on a channel derived from the AppName or module name.
  • Local listeners: notified with the effective theme and raw preference on every change.


Error handling

  • Ignores localStorage errors (e.g. privacy modes) and falls back to system-default.
  • Reports listener errors via console.error without breaking dispatch to other subscribers.
  • Validates theme inputs to prevent invalid states.


Notes

  • No dependencies — works in any modern browser without external libraries.
  • Performance — minimizes DOM writes and caches the resolved storage key.
  • Privacy — handles localStorage restrictions gracefully.
  • Extensibility — the OnChange system integrates easily with any UI.


Limitations

  • Theme application is limited to the <html data-theme> attribute; dark/light styling must be provided via your own CSS.
  • Cross-tab sync uses BroadcastChannel when available and falls back to the storage event otherwise.
  • Preferences are stored per browser/device; Dispose intentionally does not clear them.

1.4.0

Overview


TrueShade is a lightweight, dependency-free JavaScript module that manages UI color schemes (dark / light) for web applications. It persists the user's preference in localStorage, applies it to the <html> element via the data-theme attribute, reacts instantly to system color-scheme changes, and keeps every open tab in sync. It supports three modes: system-default, dark, and light.

Heads up: TrueShade is the logic and synchronization layer only — it does not ship dark/light CSS. You write your styles against the <html data-theme="dark|light"> attribute that TrueShade sets for you.


Purpose

  • Manage UI themes — switch between dark and light based on user or system preference.
  • Persistence — store the preference in localStorage under a module- or app-specific key.
  • System integration — follow OS-level changes via prefers-color-scheme.
  • Cross-tab & cross-app sync — keep the theme aligned across tabs, and optionally across multiple front-ends that share the same AppName.
  • Event-driven — notify subscribers the moment the theme changes.


Key Features

  • AppName support — initialize with an optional AppName to share preferences across front-ends in the same portal.
  • Idempotent lifecycle — safe initialization and disposal, with no duplicate listeners.
  • System-default support — resolves system-default to the live OS preference and updates the instant it changes.
  • Reliable cross-tab sync — uses BroadcastChannel where available, with an automatic storage-event fallback so no tab is left out of sync.
  • Event subscription — OnChange delivers both the resolved theme and the raw preference, with an opt-in immediate fire.
  • Minimal footprint — no dependencies, strict-mode JavaScript.
  • Error resilience — degrades gracefully when localStorage or BroadcastChannel are unavailable (e.g. privacy modes).


Installation

Install TrueShade from the OutSystems Forge.


Usage

Initialization

There are two ways to initialize TrueShade:

  • Simpler setup (recommended) — add the TrueShade Block directly to your Layout Block; it handles initialization and disposal automatically.
  • Manual setup — run the Initialize client action in your Layout Block's On Ready event, and call Dispose in On Destroy.

Pass an optional AppName to Initialize when several modules should share one preference.


Getting the current theme

Effective theme (dark or light) — client action GetLayoutColorScheme.

Raw stored preference (system-default, dark, or light) — client action GetStoredLayoutColorScheme.


Setting a theme

Set and persist a new theme with the client action SetLayoutColorScheme (system-default, dark, or light). Invalid values are rejected and logged as a console error.


Subscribing to theme changes

The callback receives the effective theme and the raw preference. Pass { immediate: true } to also fire once with the current theme on subscribe:

const unsubscribe = TrueShade.Theme.OnChange((effective, raw) => {
  console.log('Effective:', effective, '| Stored:', raw);
}, { immediate: true });

// Later, to unsubscribe:
unsubscribe();

Preventing the theme flash (FOUC)

Because the theme is applied during initialization, the page can briefly paint the wrong theme on first load. To avoid this, add a synchronous snippet to your page <head>, before any stylesheet. Replace MyApp with the AppName you pass to Initialize:

<script>
  (function () {
    try {
      var raw = localStorage.getItem('MyApp$layout-theme') || 'system-default';
      var dark = raw === 'dark' ||
        (raw === 'system-default' && matchMedia('(prefers-color-scheme: dark)').matches);
      document.documentElement.dataset.theme = dark ? 'dark' : 'light';
    } catch (e) { document.documentElement.dataset.theme = 'light'; }
  })();
</script>

Use GetStorageKey() to confirm the exact key at runtime.

Clean up

Dispose of the module to remove event listeners (the stored preference is preserved):

TrueShade.Theme.Dispose();

API Reference


Initialize(appName?)

  • Purpose: initializes the theme system (idempotent).
  • Behavior: optionally accepts appName for a shared key; seeds localStorage with system-default if unset; applies the theme to <html data-theme>; wires OS and cross-tab listeners.
  • Returns: void


GetLayoutColorScheme()

  • Purpose: returns the effective theme.
  • Behavior: resolves system-default to the current OS preference.
  • Returns: 'dark' | 'light'


GetStoredLayoutColorScheme()

  • Purpose: returns the raw stored preference.
  • Behavior: ensures the preference is seeded, returning system-default if unset.
  • Returns: 'system-default' | 'dark' | 'light'


SetLayoutColorScheme(theme)

  • Purpose: sets and persists a new theme.
  • Parameters: theme — 'system-default' | 'dark' | 'light'
  • Behavior: validates the input (logs a console error if invalid); persists to localStorage, applies to <html data-theme>, and notifies local subscribers and other tabs.
  • Returns: void


OnChange(callback, options?)

  • Purpose: subscribes to theme change events.
  • Parameters:
    • callback: (effective, raw) => void — effective is 'dark'/'light', raw is the stored preference. One-argument callbacks are also supported.
    • options (optional): { immediate: true } fires the callback once with the current theme on subscribe.
  • Behavior: a throwing callback is reported via console.error without interrupting other subscribers.
  • Returns: () => void — unsubscribe function.


GetStorageKey()

  • Purpose: returns the resolved localStorage key for the active module.
  • Returns: string — e.g. myapp$layout-theme or $OS_example$layout-theme


Dispose()

  • Purpose: cleans up resources (idempotent).
  • Behavior: removes OS and cross-tab listeners, clears the internal listener list, and preserves the stored preference.
  • Returns: void


Internal Mechanics


Storage key

  • With an AppName: <AppName>$layout-theme (e.g. myapp$layout-theme).
  • Without one (derived): $OS_<moduleName>$layout-theme, where moduleName comes from the URL's first path segment (or first hostname label).
  • Example: https://example.com/app → $OS_app$layout-theme.


Theme modes

  • system-default — follows the OS prefers-color-scheme (dark or light).
  • dark — forces dark mode.
  • light — forces light mode.


Event handling

  • OS changes: listens to prefers-color-scheme via window.matchMedia; updates only when the preference is system-default.
  • Cross-tab & cross-app sync: broadcasts local changes over BroadcastChannel (with a storage-event fallback) on a channel derived from the AppName or module name.
  • Local listeners: notified with the effective theme and raw preference on every change.


Error handling

  • Ignores localStorage errors (e.g. privacy modes) and falls back to system-default.
  • Reports listener errors via console.error without breaking dispatch to other subscribers.
  • Validates theme inputs to prevent invalid states.


Notes

  • No dependencies — works in any modern browser without external libraries.
  • Performance — minimizes DOM writes and caches the resolved storage key.
  • Privacy — handles localStorage restrictions gracefully.
  • Extensibility — the OnChange system integrates easily with any UI.


Limitations

  • Theme application is limited to the <html data-theme> attribute; dark/light styling must be provided via your own CSS.
  • Cross-tab sync uses BroadcastChannel when available and falls back to the storage event otherwise.
  • Preferences are stored per browser/device; Dispose intentionally does not clear them.

1.3.0
Overview
TrueShade is a lightweight, dependency-free JavaScript module that manages UI color schemes (dark/light modes) for web applications. It persists user theme preferences in localStorage, applies them to the <html> element via the data-theme attribute, and automatically reacts to system color scheme changes. The module supports three theme modes: system-default, dark, and light.
Purpose
  • Manage UI Themes: Seamlessly switch between dark and light modes based on user or system preferences.
  • Persistence: Store theme preferences in localStorage using a module or app specific key.
  • System Integration: React to OS-level color scheme changes via prefers-color-scheme.
  • Cross-Tab & Cross-App Sync: Synchronize theme changes across tabs and optionally across multiple front-ends sharing the same AppName.
  • Event-Driven: Notify subscribers when the theme changes through a callback system.
Key Features
  • AppName Support: Initialize with an optional AppName to share theme preferences across multiple front-ends within the same portal.
  • Idempotent Lifecycle: Safe initialization and disposal without side effects.
  • Theme Persistence: Stores preferences under a key derived from either the explicit AppName or the current module name ($OS_<name>$layout-theme).
  • System Default Support: Resolves system-default to the current OS preference.
  • Minimal Footprint: No dependencies, optimized for speed and simplicity.
  • Error Resilience: Gracefully handles storage and broadcast errors (e.g., in privacy modes).
  • Event Subscription: Allows reactive UI updates based on theme changes.
Installation
Install TrueShade from the OutSystems Forge here.
Usage
Initialization

There are two ways to initialize TrueShade:

  • Manual setup
    • Run the client action Initialize in the On Ready event of your application’s Layout Block.
    • In the On Destroy event, call the client action Dispose to remove all listeners and clean up broadcasts and variables.
  • Simpler setup
    • Add the TrueShade Block directly to your Layout Block.
    • This automatically handles initialization and disposal without requiring extra logic.
Getting the Current Theme

Retrieve the effective theme (dark or light):

Client Action: GetLayoutColorScheme

Retrieve the raw stored preference (dark, light or system-default):

Client Action: GetStoredLayoutColorScheme
Setting a Theme

Set and persist a new theme (dark, light or system-default):

Client Action: SetLayoutColorScheme

Invalid theme values are rejected with a console error.

Subscribing to Theme Changes

Register a callback to handle theme changes (receives dark or light):

const unsubscribe = TrueShade.Theme.OnChange((effectiveTheme) => {
  console.log('Theme changed to:', effectiveTheme);
});
// Later, to unsubscribe:
unsubscribe();
Clean Up

Dispose of the module to remove event listeners (does not clear stored preference):

TrueShade.Theme.Dispose();
API Reference
TrueShade.Theme.Initialize(appName?)
  • Purpose: Initializes the theme system (idempotent).
  • Behavior:
    • Optionally accepts appName to define a shared key across multiple front-ends.
    • Seeds localStorage with system-default if no preference exists.
    • Applies the current theme to <html data-theme>.
    • Sets up listeners for OS color scheme changes and cross-tab updates.
  • Returns: void
TrueShade.Theme.GetLayoutColorScheme()
  • Purpose: Returns the effective theme (dark or light).
  • Behavior: Resolves system-default to the current OS preference.
  • Returns: 'dark' | 'light'
TrueShade.Theme.GetStoredLayoutColorScheme()
  • Purpose: Returns the raw stored theme preference.
  • Behavior: Ensures the preference is seeded, returning system-default if unset.
  • Returns: 'system-default' | 'dark' | 'light'
TrueShade.Theme.SetLayoutColorScheme(theme)
  • Purpose: Sets and persists a new theme.
  • Parameters:
    • theme: 'system-default' | 'dark' | 'light'
  • Behavior:
    • Validates the input theme; logs an error for invalid values.
    • Persists to localStorage and applies to <html data-theme>.
    • Notifies subscribers and other tabs via BroadcastChannel.
  • Returns: void
TrueShade.Theme.Dispose()
  • Purpose: Cleans up resources (idempotent).
  • Behavior:
    • Removes OS and channel event listeners.
    • Clears internal listener array.
    • Preserves stored preference.
  • Returns: void
TrueShade.Theme.OnChange(callback)
  • Purpose: Subscribes to theme change events.
  • Parameters:
    • callback: (effective: string) => void - Receives 'dark' or 'light'.
  • Behavior: Adds the callback to the listener list; does not fire immediately.
  • Returns: () => void - Unsubscribe function.
Internal Mechanics
Storage Key
  • Format: $OS_<moduleName>$layout-theme
  • moduleName: Derived from the URL’s pathname (first segment) or hostname (first label), wrapped as $OS_<name>$.
  • Example: For https://example.com/app, the key might be $OS_app$layout-theme.
Theme Modes
  • system-default: Resolves to the OS’s prefers-color-scheme (dark or light).
  • dark: Forces dark mode.
  • light: Forces light mode.
Event Handling
  • OS Changes: Listens to prefers-color-scheme changes via window.matchMedia. Updates the theme only if the preference is system-default.
  • Cross-Tab & Cross-App Sync: Uses BroadcastChannel with a key derived from the AppName or module name.
  • Local Listeners: Notifies registered callbacks with the effective theme (dark or light) on changes.
Error Handling
  • Ignores localStorage errors (e.g., in privacy modes) and falls back to system-default.
  • Swallows listener and channel errors to ensure stability.
  • Validates theme inputs to prevent invalid states.
Notes
  • No Dependencies: Works in any modern browser without external libraries.
  • Performance: Minimizes DOM updates and allocations (e.g., caches storage keys).
  • Privacy: Gracefully handles localStorage restrictions.
  • Extensibility: The onChange system allows easy integration with UI frameworks.
Limitations
  • Requires modern browser support for window.matchMedia and BroadcastChannel (falls back gracefully if unavailable).
  • Does not clear localStorage on Dispose to preserve user preferences.
  • Theme application is limited to the <html data-theme> attribute; custom styling must be implemented via CSS.

1.2.3
Overview
TrueShade is a lightweight, dependency-free JavaScript module that manages UI color schemes (dark/light modes) for web applications. It persists user theme preferences in localStorage, applies them to the <html> element via the data-theme attribute, and automatically reacts to system color scheme changes. The module supports three theme modes: system-default, dark, and light.
Purpose
  • Manage UI Themes: Seamlessly switch between dark and light modes based on user or system preferences.
  • Persistence: Store theme preferences in localStorage using a module or app specific key.
  • System Integration: React to OS-level color scheme changes via prefers-color-scheme.
  • Cross-Tab & Cross-App Sync: Synchronize theme changes across tabs and optionally across multiple front-ends sharing the same AppName.
  • Event-Driven: Notify subscribers when the theme changes through a callback system.
Key Features
  • AppName Support: Initialize with an optional AppName to share theme preferences across multiple front-ends within the same portal.
  • Idempotent Lifecycle: Safe initialization and disposal without side effects.
  • Theme Persistence: Stores preferences under a key derived from either the explicit AppName or the current module name ($OS_<name>$layout-theme).
  • System Default Support: Resolves system-default to the current OS preference.
  • Minimal Footprint: No dependencies, optimized for speed and simplicity.
  • Error Resilience: Gracefully handles storage and broadcast errors (e.g., in privacy modes).
  • Event Subscription: Allows reactive UI updates based on theme changes.
Installation
Install TrueShade from the OutSystems Forge here.
Usage
Initialization

There are two ways to initialize TrueShade:

  • Manual setup
    • Run the client action Initialize in the On Ready event of your application’s Layout Block.
    • In the On Destroy event, call the client action Dispose to remove all listeners and clean up broadcasts and variables.
  • Simpler setup
    • Add the TrueShade Block directly to your Layout Block.
    • This automatically handles initialization and disposal without requiring extra logic.
Getting the Current Theme

Retrieve the effective theme (dark or light):

Client Action: GetLayoutColorScheme

Retrieve the raw stored preference (dark, light or system-default):

Client Action: GetStoredLayoutColorScheme
Setting a Theme

Set and persist a new theme (dark, light or system-default):

Client Action: SetLayoutColorScheme

Invalid theme values are rejected with a console error.

Subscribing to Theme Changes

Register a callback to handle theme changes (receives dark or light):

const unsubscribe = TrueShade.Theme.OnChange((effectiveTheme) => {
  console.log('Theme changed to:', effectiveTheme);
});
// Later, to unsubscribe:
unsubscribe();
Clean Up

Dispose of the module to remove event listeners (does not clear stored preference):

TrueShade.Theme.Dispose();
API Reference
TrueShade.Theme.Initialize(appName?)
  • Purpose: Initializes the theme system (idempotent).
  • Behavior:
    • Optionally accepts appName to define a shared key across multiple front-ends.
    • Seeds localStorage with system-default if no preference exists.
    • Applies the current theme to <html data-theme>.
    • Sets up listeners for OS color scheme changes and cross-tab updates.
  • Returns: void
TrueShade.Theme.GetLayoutColorScheme()
  • Purpose: Returns the effective theme (dark or light).
  • Behavior: Resolves system-default to the current OS preference.
  • Returns: 'dark' | 'light'
TrueShade.Theme.GetStoredLayoutColorScheme()
  • Purpose: Returns the raw stored theme preference.
  • Behavior: Ensures the preference is seeded, returning system-default if unset.
  • Returns: 'system-default' | 'dark' | 'light'
TrueShade.Theme.SetLayoutColorScheme(theme)
  • Purpose: Sets and persists a new theme.
  • Parameters:
    • theme: 'system-default' | 'dark' | 'light'
  • Behavior:
    • Validates the input theme; logs an error for invalid values.
    • Persists to localStorage and applies to <html data-theme>.
    • Notifies subscribers and other tabs via BroadcastChannel.
  • Returns: void
TrueShade.Theme.Dispose()
  • Purpose: Cleans up resources (idempotent).
  • Behavior:
    • Removes OS and channel event listeners.
    • Clears internal listener array.
    • Preserves stored preference.
  • Returns: void
TrueShade.Theme.OnChange(callback)
  • Purpose: Subscribes to theme change events.
  • Parameters:
    • callback: (effective: string) => void - Receives 'dark' or 'light'.
  • Behavior: Adds the callback to the listener list; does not fire immediately.
  • Returns: () => void - Unsubscribe function.
Internal Mechanics
Storage Key
  • Format: $OS_<moduleName>$layout-theme
  • moduleName: Derived from the URL’s pathname (first segment) or hostname (first label), wrapped as $OS_<name>$.
  • Example: For https://example.com/app, the key might be $OS_app$layout-theme.
Theme Modes
  • system-default: Resolves to the OS’s prefers-color-scheme (dark or light).
  • dark: Forces dark mode.
  • light: Forces light mode.
Event Handling
  • OS Changes: Listens to prefers-color-scheme changes via window.matchMedia. Updates the theme only if the preference is system-default.
  • Cross-Tab & Cross-App Sync: Uses BroadcastChannel with a key derived from the AppName or module name.
  • Local Listeners: Notifies registered callbacks with the effective theme (dark or light) on changes.
Error Handling
  • Ignores localStorage errors (e.g., in privacy modes) and falls back to system-default.
  • Swallows listener and channel errors to ensure stability.
  • Validates theme inputs to prevent invalid states.
Notes
  • No Dependencies: Works in any modern browser without external libraries.
  • Performance: Minimizes DOM updates and allocations (e.g., caches storage keys).
  • Privacy: Gracefully handles localStorage restrictions.
  • Extensibility: The onChange system allows easy integration with UI frameworks.
Limitations
  • Requires modern browser support for window.matchMedia and BroadcastChannel (falls back gracefully if unavailable).
  • Does not clear localStorage on Dispose to preserve user preferences.
  • Theme application is limited to the <html data-theme> attribute; custom styling must be implemented via CSS.

1.2.2
Overview
TrueShade is a lightweight, dependency-free JavaScript module that manages UI color schemes (dark/light modes) for web applications. It persists user theme preferences in localStorage, applies them to the <html> element via the data-theme attribute, and automatically reacts to system color scheme changes. The module supports three theme modes: system-default, dark, and light.
Purpose
  • Manage UI Themes: Seamlessly switch between dark and light modes based on user or system preferences.
  • Persistence: Store theme preferences in localStorage using a module or app specific key.
  • System Integration: React to OS-level color scheme changes via prefers-color-scheme.
  • Cross-Tab & Cross-App Sync: Synchronize theme changes across tabs and optionally across multiple front-ends sharing the same AppName.
  • Event-Driven: Notify subscribers when the theme changes through a callback system.
Key Features
  • AppName Support: Initialize with an optional AppName to share theme preferences across multiple front-ends within the same portal.
  • Idempotent Lifecycle: Safe initialization and disposal without side effects.
  • Theme Persistence: Stores preferences under a key derived from either the explicit AppName or the current module name ($OS_<name>$layout-theme).
  • System Default Support: Resolves system-default to the current OS preference.
  • Minimal Footprint: No dependencies, optimized for speed and simplicity.
  • Error Resilience: Gracefully handles storage and broadcast errors (e.g., in privacy modes).
  • Event Subscription: Allows reactive UI updates based on theme changes.
Installation
Install TrueShade from the OutSystems Forge here.
Usage
Initialization

There are two ways to initialize TrueShade:

  • Manual setup
    • Run the client action Initialize in the On Ready event of your application’s Layout Block.
    • In the On Destroy event, call the client action Dispose to remove all listeners and clean up broadcasts and variables.
  • Simpler setup
    • Add the TrueShade Block directly to your Layout Block.
    • This automatically handles initialization and disposal without requiring extra logic.
Getting the Current Theme

Retrieve the effective theme (dark or light):

Client Action: GetLayoutColorScheme

Retrieve the raw stored preference (dark, light or system-default):

Client Action: GetStoredLayoutColorScheme
Setting a Theme

Set and persist a new theme (dark, light or system-default):

Client Action: SetLayoutColorScheme

Invalid theme values are rejected with a console error.

Subscribing to Theme Changes

Register a callback to handle theme changes (receives dark or light):

const unsubscribe = TrueShade.Theme.OnChange((effectiveTheme) => {
  console.log('Theme changed to:', effectiveTheme);
});
// Later, to unsubscribe:
unsubscribe();
Clean Up

Dispose of the module to remove event listeners (does not clear stored preference):

TrueShade.Theme.Dispose();
API Reference
TrueShade.Theme.Initialize(appName?)
  • Purpose: Initializes the theme system (idempotent).
  • Behavior:
    • Optionally accepts appName to define a shared key across multiple front-ends.
    • Seeds localStorage with system-default if no preference exists.
    • Applies the current theme to <html data-theme>.
    • Sets up listeners for OS color scheme changes and cross-tab updates.
  • Returns: void
TrueShade.Theme.GetLayoutColorScheme()
  • Purpose: Returns the effective theme (dark or light).
  • Behavior: Resolves system-default to the current OS preference.
  • Returns: 'dark' | 'light'
TrueShade.Theme.GetStoredLayoutColorScheme()
  • Purpose: Returns the raw stored theme preference.
  • Behavior: Ensures the preference is seeded, returning system-default if unset.
  • Returns: 'system-default' | 'dark' | 'light'
TrueShade.Theme.SetLayoutColorScheme(theme)
  • Purpose: Sets and persists a new theme.
  • Parameters:
    • theme: 'system-default' | 'dark' | 'light'
  • Behavior:
    • Validates the input theme; logs an error for invalid values.
    • Persists to localStorage and applies to <html data-theme>.
    • Notifies subscribers and other tabs via BroadcastChannel.
  • Returns: void
TrueShade.Theme.Dispose()
  • Purpose: Cleans up resources (idempotent).
  • Behavior:
    • Removes OS and channel event listeners.
    • Clears internal listener array.
    • Preserves stored preference.
  • Returns: void
TrueShade.Theme.OnChange(callback)
  • Purpose: Subscribes to theme change events.
  • Parameters:
    • callback: (effective: string) => void - Receives 'dark' or 'light'.
  • Behavior: Adds the callback to the listener list; does not fire immediately.
  • Returns: () => void - Unsubscribe function.
Internal Mechanics
Storage Key
  • Format: $OS_<moduleName>$layout-theme
  • moduleName: Derived from the URL’s pathname (first segment) or hostname (first label), wrapped as $OS_<name>$.
  • Example: For https://example.com/app, the key might be $OS_app$layout-theme.
Theme Modes
  • system-default: Resolves to the OS’s prefers-color-scheme (dark or light).
  • dark: Forces dark mode.
  • light: Forces light mode.
Event Handling
  • OS Changes: Listens to prefers-color-scheme changes via window.matchMedia. Updates the theme only if the preference is system-default.
  • Cross-Tab & Cross-App Sync: Uses BroadcastChannel with a key derived from the AppName or module name.
  • Local Listeners: Notifies registered callbacks with the effective theme (dark or light) on changes.
Error Handling
  • Ignores localStorage errors (e.g., in privacy modes) and falls back to system-default.
  • Swallows listener and channel errors to ensure stability.
  • Validates theme inputs to prevent invalid states.
Notes
  • No Dependencies: Works in any modern browser without external libraries.
  • Performance: Minimizes DOM updates and allocations (e.g., caches storage keys).
  • Privacy: Gracefully handles localStorage restrictions.
  • Extensibility: The onChange system allows easy integration with UI frameworks.
Limitations
  • Requires modern browser support for window.matchMedia and BroadcastChannel (falls back gracefully if unavailable).
  • Does not clear localStorage on Dispose to preserve user preferences.
  • Theme application is limited to the <html data-theme> attribute; custom styling must be implemented via CSS.

1.2.1
Overview
TrueShade is a lightweight, dependency-free JavaScript module that manages UI color schemes (dark/light modes) for web applications. It persists user theme preferences in localStorage, applies them to the <html> element via the data-theme attribute, and automatically reacts to system color scheme changes. The module supports three theme modes: system-default, dark, and light.
Purpose
  • Manage UI Themes: Seamlessly switch between dark and light modes based on user or system preferences.
  • Persistence: Store theme preferences in localStorage using a module or app specific key.
  • System Integration: React to OS-level color scheme changes via prefers-color-scheme.
  • Cross-Tab & Cross-App Sync: Synchronize theme changes across tabs and optionally across multiple front-ends sharing the same AppName.
  • Event-Driven: Notify subscribers when the theme changes through a callback system.
Key Features
  • AppName Support: Initialize with an optional AppName to share theme preferences across multiple front-ends within the same portal.
  • Idempotent Lifecycle: Safe initialization and disposal without side effects.
  • Theme Persistence: Stores preferences under a key derived from either the explicit AppName or the current module name ($OS_<name>$layout-theme).
  • System Default Support: Resolves system-default to the current OS preference.
  • Minimal Footprint: No dependencies, optimized for speed and simplicity.
  • Error Resilience: Gracefully handles storage and broadcast errors (e.g., in privacy modes).
  • Event Subscription: Allows reactive UI updates based on theme changes.
Installation
Install TrueShade from the OutSystems Forge here.
Usage
Initialization

There are two ways to initialize TrueShade:

  • Manual setup
    • Run the client action Initialize in the On Ready event of your application’s Layout Block.
    • In the On Destroy event, call the client action Dispose to remove all listeners and clean up broadcasts and variables.
  • Simpler setup
    • Add the TrueShade Block directly to your Layout Block.
    • This automatically handles initialization and disposal without requiring extra logic.
Getting the Current Theme

Retrieve the effective theme (dark or light):

Client Action: GetLayoutColorScheme

Retrieve the raw stored preference (dark, light or system-default):

Client Action: GetStoredLayoutColorScheme
Setting a Theme

Set and persist a new theme (dark, light or system-default):

Client Action: SetLayoutColorScheme

Invalid theme values are rejected with a console error.

Subscribing to Theme Changes

Register a callback to handle theme changes (receives dark or light):

const unsubscribe = TrueShade.Theme.OnChange((effectiveTheme) => {
  console.log('Theme changed to:', effectiveTheme);
});
// Later, to unsubscribe:
unsubscribe();
Clean Up

Dispose of the module to remove event listeners (does not clear stored preference):

TrueShade.Theme.Dispose();
API Reference
TrueShade.Theme.Initialize(appName?)
  • Purpose: Initializes the theme system (idempotent).
  • Behavior:
    • Optionally accepts appName to define a shared key across multiple front-ends.
    • Seeds localStorage with system-default if no preference exists.
    • Applies the current theme to <html data-theme>.
    • Sets up listeners for OS color scheme changes and cross-tab updates.
  • Returns: void
TrueShade.Theme.GetLayoutColorScheme()
  • Purpose: Returns the effective theme (dark or light).
  • Behavior: Resolves system-default to the current OS preference.
  • Returns: 'dark' | 'light'
TrueShade.Theme.GetStoredLayoutColorScheme()
  • Purpose: Returns the raw stored theme preference.
  • Behavior: Ensures the preference is seeded, returning system-default if unset.
  • Returns: 'system-default' | 'dark' | 'light'
TrueShade.Theme.SetLayoutColorScheme(theme)
  • Purpose: Sets and persists a new theme.
  • Parameters:
    • theme: 'system-default' | 'dark' | 'light'
  • Behavior:
    • Validates the input theme; logs an error for invalid values.
    • Persists to localStorage and applies to <html data-theme>.
    • Notifies subscribers and other tabs via BroadcastChannel.
  • Returns: void
TrueShade.Theme.Dispose()
  • Purpose: Cleans up resources (idempotent).
  • Behavior:
    • Removes OS and channel event listeners.
    • Clears internal listener array.
    • Preserves stored preference.
  • Returns: void
TrueShade.Theme.OnChange(callback)
  • Purpose: Subscribes to theme change events.
  • Parameters:
    • callback: (effective: string) => void - Receives 'dark' or 'light'.
  • Behavior: Adds the callback to the listener list; does not fire immediately.
  • Returns: () => void - Unsubscribe function.
Internal Mechanics
Storage Key
  • Format: $OS_<moduleName>$layout-theme
  • moduleName: Derived from the URL’s pathname (first segment) or hostname (first label), wrapped as $OS_<name>$.
  • Example: For https://example.com/app, the key might be $OS_app$layout-theme.
Theme Modes
  • system-default: Resolves to the OS’s prefers-color-scheme (dark or light).
  • dark: Forces dark mode.
  • light: Forces light mode.
Event Handling
  • OS Changes: Listens to prefers-color-scheme changes via window.matchMedia. Updates the theme only if the preference is system-default.
  • Cross-Tab & Cross-App Sync: Uses BroadcastChannel with a key derived from the AppName or module name.
  • Local Listeners: Notifies registered callbacks with the effective theme (dark or light) on changes.
Error Handling
  • Ignores localStorage errors (e.g., in privacy modes) and falls back to system-default.
  • Swallows listener and channel errors to ensure stability.
  • Validates theme inputs to prevent invalid states.
Notes
  • No Dependencies: Works in any modern browser without external libraries.
  • Performance: Minimizes DOM updates and allocations (e.g., caches storage keys).
  • Privacy: Gracefully handles localStorage restrictions.
  • Extensibility: The onChange system allows easy integration with UI frameworks.
Limitations
  • Requires modern browser support for window.matchMedia and BroadcastChannel (falls back gracefully if unavailable).
  • Does not clear localStorage on Dispose to preserve user preferences.
  • Theme application is limited to the <html data-theme> attribute; custom styling must be implemented via CSS.

1.2.0
Overview
TrueShade is a lightweight, dependency-free JavaScript module that manages UI color schemes (dark/light modes) for web applications. It persists user theme preferences in localStorage, applies them to the <html> element via the data-theme attribute, and automatically reacts to system color scheme changes. The module supports three theme modes: system-defaultdark, and light.
Purpose
  • Manage UI Themes: Seamlessly switch between dark and light modes based on user or system preferences.
  • Persistence: Store theme preferences in localStorage using a module or app specific key.
  • System Integration: React to OS-level color scheme changes via prefers-color-scheme.
  • Cross-Tab & Cross-App Sync: Synchronize theme changes across tabs and optionally across multiple front-ends sharing the same AppName.
  • Event-Driven: Notify subscribers when the theme changes through a callback system.
Key Features
  • AppName Support: Initialize with an optional AppName to share theme preferences across multiple front-ends within the same portal.
  • Idempotent Lifecycle: Safe initialization and disposal without side effects.
  • Theme Persistence: Stores preferences under a key derived from either the explicit AppName or the current module name ($OS_<name>$layout-theme).
  • System Default Support: Resolves system-default to the current OS preference.
  • Minimal Footprint: No dependencies, optimized for speed and simplicity.
  • Error Resilience: Gracefully handles storage and broadcast errors (e.g., in privacy modes).
  • Event Subscription: Allows reactive UI updates based on theme changes.
Installation
Install TrueShade from the OutSystems Forge here.
Usage
Initialization

There are two ways to initialize TrueShade:

  • Manual setup
    • Run the client action Initialize in the On Ready event of your application’s Layout Block.
    • In the On Destroy event, call the client action Dispose to remove all listeners and clean up broadcasts and variables.
  • Simpler setup
    • Add the TrueShade Block directly to your Layout Block.
    • This automatically handles initialization and disposal without requiring extra logic.
Getting the Current Theme

Retrieve the effective theme (dark or light):

Client Action: GetLayoutColorScheme

Retrieve the raw stored preference (darklight or system-default):

Client Action: GetStoredLayoutColorScheme
Setting a Theme

Set and persist a new theme (darklight or system-default):

Client Action: SetLayoutColorScheme

Invalid theme values are rejected with a console error.

Subscribing to Theme Changes

Register a callback to handle theme changes (receives dark or light):

const unsubscribe = TrueShade.Theme.OnChange((effectiveTheme) => {
  console.log('Theme changed to:', effectiveTheme);
});
// Later, to unsubscribe:
unsubscribe();
Clean Up

Dispose of the module to remove event listeners (does not clear stored preference):

TrueShade.Theme.Dispose();
API Reference
TrueShade.Theme.Initialize(appName?)
  • Purpose: Initializes the theme system (idempotent).
  • Behavior:
    • Optionally accepts appName to define a shared key across multiple front-ends.
    • Seeds localStorage with system-default if no preference exists.
    • Applies the current theme to <html data-theme>.
    • Sets up listeners for OS color scheme changes and cross-tab updates.
  • Returnsvoid
TrueShade.Theme.GetLayoutColorScheme()
  • Purpose: Returns the effective theme (dark or light).
  • Behavior: Resolves system-default to the current OS preference.
  • Returns'dark' | 'light'
TrueShade.Theme.GetStoredLayoutColorScheme()
  • Purpose: Returns the raw stored theme preference.
  • Behavior: Ensures the preference is seeded, returning system-default if unset.
  • Returns'system-default' | 'dark' | 'light'
TrueShade.Theme.SetLayoutColorScheme(theme)
  • Purpose: Sets and persists a new theme.
  • Parameters:
    • theme'system-default' | 'dark' | 'light'
  • Behavior:
    • Validates the input theme; logs an error for invalid values.
    • Persists to localStorage and applies to <html data-theme>.
    • Notifies subscribers and other tabs via BroadcastChannel.
  • Returnsvoid
TrueShade.Theme.Dispose()
  • Purpose: Cleans up resources (idempotent).
  • Behavior:
    • Removes OS and channel event listeners.
    • Clears internal listener array.
    • Preserves stored preference.
  • Returnsvoid
TrueShade.Theme.OnChange(callback)
  • Purpose: Subscribes to theme change events.
  • Parameters:
    • callback(effective: string) => void - Receives 'dark' or 'light'.
  • Behavior: Adds the callback to the listener list; does not fire immediately.
  • Returns() => void - Unsubscribe function.
Internal Mechanics
Storage Key
  • Format$OS_<moduleName>$layout-theme
  • moduleName: Derived from the URL’s pathname (first segment) or hostname (first label), wrapped as $OS_<name>$.
  • Example: For https://example.com/app, the key might be $OS_app$layout-theme.
Theme Modes
  • system-default: Resolves to the OS’s prefers-color-scheme (dark or light).
  • dark: Forces dark mode.
  • light: Forces light mode.
Event Handling
  • OS Changes: Listens to prefers-color-scheme changes via window.matchMedia. Updates the theme only if the preference is system-default.
  • Cross-Tab & Cross-App Sync: Uses BroadcastChannel with a key derived from the AppName or module name.
  • Local Listeners: Notifies registered callbacks with the effective theme (dark or light) on changes.
Error Handling
  • Ignores localStorage errors (e.g., in privacy modes) and falls back to system-default.
  • Swallows listener and channel errors to ensure stability.
  • Validates theme inputs to prevent invalid states.
Notes
  • No Dependencies: Works in any modern browser without external libraries.
  • Performance: Minimizes DOM updates and allocations (e.g., caches storage keys).
  • Privacy: Gracefully handles localStorage restrictions.
  • Extensibility: The onChange system allows easy integration with UI frameworks.
Limitations
  • Requires modern browser support for window.matchMedia and BroadcastChannel (falls back gracefully if unavailable).
  • Does not clear localStorage on Dispose to preserve user preferences.
  • Theme application is limited to the <html data-theme> attribute; custom styling must be implemented via CSS.

1.1.1
Overview
TrueShade is a lightweight, dependency-free JavaScript module designed to manage UI color schemes (dark/light modes) for web applications. It persists user theme preferences in localStorage, applies them to the <html> element via the data-theme attribute, and responds to system color scheme changes. The module supports three theme modes: system-default, dark, and light.
Purpose
  • Manage UI Themes: Seamlessly switch between dark and light modes based on user preference or system settings.
  • Persistence: Store theme preferences in localStorage using a module-specific key.
  • System Integration: React to OS-level color scheme changes via prefers-color-scheme.
  • Cross-Tab Sync: Use BroadcastChannel for theme synchronization across tabs.
  • Event-Driven: Notify subscribers of theme changes via a callback system.
Key Features
  • Idempotent Lifecycle: Safe initialization and disposal without side effects.
  • Theme Persistence: Stores preferences under a module-specific key ($OS_<name>$layout-theme).
  • System Default Support: Resolves system-default to the OS’s current color scheme.
  • Minimal Footprint: No external dependencies, optimized for performance.
  • Error Resilience: Handles storage errors gracefully (e.g., in privacy modes).
  • Event Subscription: Allows components to react to theme changes dynamically.
Installation
Install TrueShade from the OutSystems Forge here.
Usage
Initialization

To set up the theme system, you can choose one of two approaches:

  • Manual setup
    • Run the client action Initialize in the On Ready event of your application’s Layout Block.
    • In the On Destroy event, call the client action Dispose to remove all listeners and clean up broadcasts and variables.
  • Simpler setup
    • Add the TrueShade Block directly to your Layout Block.
    • This automatically handles initialization and disposal without requiring extra logic.
Getting the Current Theme

Retrieve the effective theme (dark or light):

Client Action: GetLayoutColorScheme

Retrieve the raw stored preference (dark, light or system-default):

Client Action: GetStoredLayoutColorScheme
Setting a Theme

Set and persist a new theme (dark, light or system-default):

Client Action: SetLayoutColorScheme

Invalid theme values are rejected with a console error.

Subscribing to Theme Changes

Register a callback to handle theme changes (receives dark or light):

const unsubscribe = TrueShade.Theme.OnChange((effectiveTheme) => {
  console.log('Theme changed to:', effectiveTheme);
});
// Later, to unsubscribe:
unsubscribe();
Clean Up

Dispose of the module to remove event listeners (does not clear stored preference):

TrueShade.Theme.Dispose();
API Reference
TrueShade.Theme.Initialize()
  • Purpose: Initializes the theme system (idempotent).
  • Behavior:
    • Seeds localStorage with system-default if no preference exists.
    • Applies the current theme to <html data-theme>.
    • Sets up listeners for OS color scheme changes and cross-tab updates.
  • Returns: void
TrueShade.Theme.GetLayoutColorScheme()
  • Purpose: Returns the effective theme (dark or light).
  • Behavior: Resolves system-default to the current OS preference.
  • Returns: 'dark' | 'light'
TrueShade.Theme.GetStoredLayoutColorScheme()
  • Purpose: Returns the raw stored theme preference.
  • Behavior: Ensures the preference is seeded, returning system-default if unset.
  • Returns: 'system-default' | 'dark' | 'light'
TrueShade.Theme.SetLayoutColorScheme(theme)
  • Purpose: Sets and persists a new theme.
  • Parameters:
    • theme: 'system-default' | 'dark' | 'light'
  • Behavior:
    • Validates the input theme; logs an error for invalid values.
    • Persists to localStorage and applies to <html data-theme>.
    • Notifies subscribers and other tabs via BroadcastChannel.
  • Returns: void
TrueShade.Theme.Dispose()
  • Purpose: Cleans up resources (idempotent).
  • Behavior:
    • Removes OS and channel event listeners.
    • Clears internal listener array.
    • Preserves stored preference.
  • Returns: void
TrueShade.Theme.OnChange(callback)
  • Purpose: Subscribes to theme change events.
  • Parameters:
    • callback: (effective: string) => void - Receives 'dark' or 'light'.
  • Behavior: Adds the callback to the listener list; does not fire immediately.
  • Returns: () => void - Unsubscribe function.
Internal Mechanics
Storage Key
  • Format: $OS_<moduleName>$layout-theme
  • moduleName: Derived from the URL’s pathname (first segment) or hostname (first label), wrapped as $OS_<name>$.
  • Example: For https://example.com/app, the key might be $OS_app$layout-theme.
Theme Modes
  • system-default: Resolves to the OS’s prefers-color-scheme (dark or light).
  • dark: Forces dark mode.
  • light: Forces light mode.
Event Handling
  • OS Changes: Listens to prefers-color-scheme changes via window.matchMedia. Updates the theme only if the preference is system-default.
  • Cross-Tab Sync: Uses BroadcastChannel (if available) to synchronize theme changes across tabs.
  • Local Listeners: Notifies registered callbacks with the effective theme (dark or light) on changes.
Error Handling
  • Ignores localStorage errors (e.g., in privacy modes) and falls back to system-default.
  • Swallows listener and channel errors to ensure stability.
  • Validates theme inputs to prevent invalid states.
Notes
  • No Dependencies: Works in any modern browser without external libraries.
  • Performance: Minimizes DOM updates and allocations (e.g., caches storage keys).
  • Privacy: Gracefully handles localStorage restrictions.
  • Extensibility: The onChange system allows easy integration with UI frameworks.
Limitations
  • Requires modern browser support for window.matchMedia and BroadcastChannel (falls back gracefully if unavailable).
  • Does not clear localStorage on Dispose to preserve user preferences.
  • Theme application is limited to the <html data-theme> attribute; custom styling must be implemented via CSS.

1.1.0
Overview
TrueShade is a lightweight, dependency-free JavaScript module designed to manage UI color schemes (dark/light modes) for web applications. It persists user theme preferences in localStorage, applies them to the <html> element via the data-theme attribute, and responds to system color scheme changes. The module supports three theme modes: system-defaultdark, and light.
Purpose
  • Manage UI Themes: Seamlessly switch between dark and light modes based on user preference or system settings.
  • Persistence: Store theme preferences in localStorage using a module-specific key.
  • System Integration: React to OS-level color scheme changes via prefers-color-scheme.
  • Cross-Tab Sync: Use BroadcastChannel for theme synchronization across tabs.
  • Event-Driven: Notify subscribers of theme changes via a callback system.
Key Features
  • Idempotent Lifecycle: Safe initialization and disposal without side effects.
  • Theme Persistence: Stores preferences under a module-specific key ($OS_<name>$layout-theme).
  • System Default Support: Resolves system-default to the OS’s current color scheme.
  • Minimal Footprint: No external dependencies, optimized for performance.
  • Error Resilience: Handles storage errors gracefully (e.g., in privacy modes).
  • Event Subscription: Allows components to react to theme changes dynamically.
Installation
Install TrueShade from the OutSystems Forge here.
Usage
Initialization

To set up the theme system, you can choose one of two approaches:

  • Manual setup
    • Run the client action Initialize in the On Ready event of your application’s Layout Block.
    • In the On Destroy event, call the client action Dispose to remove all listeners and clean up broadcasts and variables.
  • Simpler setup
    • Add the TrueShade Block directly to your Layout Block.
    • This automatically handles initialization and disposal without requiring extra logic.
Getting the Current Theme

Retrieve the effective theme (dark or light):

Client Action: GetLayoutColorScheme

Retrieve the raw stored preference (darklight or system-default):

Client Action: GetStoredLayoutColorScheme
Setting a Theme

Set and persist a new theme (darklight or system-default):

Client Action: SetLayoutColorScheme

Invalid theme values are rejected with a console error.

Subscribing to Theme Changes

Register a callback to handle theme changes (receives dark or light):

const unsubscribe = TrueShade.Theme.OnChange((effectiveTheme) => {
  console.log('Theme changed to:', effectiveTheme);
});
// Later, to unsubscribe:
unsubscribe();
Clean Up

Dispose of the module to remove event listeners (does not clear stored preference):

TrueShade.Theme.Dispose();
API Reference
TrueShade.Theme.Initialize()
  • Purpose: Initializes the theme system (idempotent).
  • Behavior:
    • Seeds localStorage with system-default if no preference exists.
    • Applies the current theme to <html data-theme>.
    • Sets up listeners for OS color scheme changes and cross-tab updates.
  • Returnsvoid
TrueShade.Theme.GetLayoutColorScheme()
  • Purpose: Returns the effective theme (dark or light).
  • Behavior: Resolves system-default to the current OS preference.
  • Returns'dark' | 'light'
TrueShade.Theme.GetStoredLayoutColorScheme()
  • Purpose: Returns the raw stored theme preference.
  • Behavior: Ensures the preference is seeded, returning system-default if unset.
  • Returns'system-default' | 'dark' | 'light'
TrueShade.Theme.SetLayoutColorScheme(theme)
  • Purpose: Sets and persists a new theme.
  • Parameters:
    • theme'system-default' | 'dark' | 'light'
  • Behavior:
    • Validates the input theme; logs an error for invalid values.
    • Persists to localStorage and applies to <html data-theme>.
    • Notifies subscribers and other tabs via BroadcastChannel.
  • Returnsvoid
TrueShade.Theme.Dispose()
  • Purpose: Cleans up resources (idempotent).
  • Behavior:
    • Removes OS and channel event listeners.
    • Clears internal listener array.
    • Preserves stored preference.
  • Returnsvoid
TrueShade.Theme.OnChange(callback)
  • Purpose: Subscribes to theme change events.
  • Parameters:
    • callback(effective: string) => void - Receives 'dark' or 'light'.
  • Behavior: Adds the callback to the listener list; does not fire immediately.
  • Returns() => void - Unsubscribe function.
Internal Mechanics
Storage Key
  • Format$OS_<moduleName>$layout-theme
  • moduleName: Derived from the URL’s pathname (first segment) or hostname (first label), wrapped as $OS_<name>$.
  • Example: For https://example.com/app, the key might be $OS_app$layout-theme.
Theme Modes
  • system-default: Resolves to the OS’s prefers-color-scheme (dark or light).
  • dark: Forces dark mode.
  • light: Forces light mode.
Event Handling
  • OS Changes: Listens to prefers-color-scheme changes via window.matchMedia. Updates the theme only if the preference is system-default.
  • Cross-Tab Sync: Uses BroadcastChannel (if available) to synchronize theme changes across tabs.
  • Local Listeners: Notifies registered callbacks with the effective theme (dark or light) on changes.
Error Handling
  • Ignores localStorage errors (e.g., in privacy modes) and falls back to system-default.
  • Swallows listener and channel errors to ensure stability.
  • Validates theme inputs to prevent invalid states.
Notes
  • No Dependencies: Works in any modern browser without external libraries.
  • Performance: Minimizes DOM updates and allocations (e.g., caches storage keys).
  • Privacy: Gracefully handles localStorage restrictions.
  • Extensibility: The onChange system allows easy integration with UI frameworks.
Limitations
  • Requires modern browser support for window.matchMedia and BroadcastChannel (falls back gracefully if unavailable).
  • Does not clear localStorage on Dispose to preserve user preferences.
  • Theme application is limited to the <html data-theme> attribute; custom styling must be implemented via CSS.

1.0.2

Lightweight JavaScript utility to manage Dark / Light / System-default theme in OutSystems apps.

It works by toggling the <html data-theme> attribute and persisting the user’s choice (per module) in localStorage.



Highlights

  • Modes: system-default | dark | light

  • Auto-follows OS dark mode when set to system-default

  • Per-module key: $OS_<ModuleName>$layout-theme

  • Minimal DOM writes & zero external dependencies

  • Safe no-op if localStorage is unavailable

  • Public API exposed under TrueShade.Theme.*




Use Cases


  • Consistent Dark / Light theme switching across screens

  • Respect user’s OS preference unless explicitly overridden

  • Cross-tab synchronization via storage event




Installation


  1. Install the asset from the Forge.

  2. Call the Initialize client action in your Layout’s OnReady event.




Example of Minimal CSS (add to Theme)


html[data-theme="dark"] {

  color-scheme: dark;

  background: #111;

  color: #eee;

}


html[data-theme="light"] {

  color-scheme: light;

  background: #fff;

  color: #111;

}




Public APIs


  • TrueShade.Theme.Initialize()

  • TrueShade.Theme.GetLayoutColorScheme()

  • TrueShade.Theme.GetStoredLayoutColorScheme()

  • TrueShade.Theme.SetLayoutColorScheme(mode)

  • TrueShade.Theme.Dispose()




Behavior Details


  • Initialize()

    Idempotent. Seeds localStorage with system-default if absent, applies theme, attaches listeners for OS changes and storage events.

  • GetLayoutColorScheme()

    Returns the effective mode. If stored value is system-default, it resolves to the current OS mode (dark or light).

  • GetStoredLayoutColorScheme()

    Returns the literal stored string or null (before initialization).

  • SetLayoutColorScheme(mode)

    Accepts only system-default | dark | light. Logs console.error on invalid input.

  • Dispose()

    Removes listeners; does not delete stored preference.




Storage Key Format


  • Computed key: $OS_<ModuleName>$layout-theme


Where ModuleName is derived as follows:

  • First non-empty path segment (e.g. /Sales/Home → Sales)

  • Else first hostname label (e.g. admin.example.com → admin)

  • If empty, fallback ⇒ layout-theme




DOM Contract


  • <html data-theme="dark|light"> is always kept in sync.

  • When user selects system-default, the attribute automatically tracks OS changes.




1.0.1

TrueShade Theme Controller

Lightweight JavaScript utility to manage Dark / Light / OS‑default theme in OutSystems apps by toggling the <html data-theme> attribute and persisting the user choice (per module) in localStorage.


Highlights
   â€¢   Modes: os-default | dark | light
   â€¢   Auto-follows OS dark mode when set to os-default
   â€¢   Per‑module key: $OS_<ModuleName>$layout-theme
   â€¢   Minimal DOM writes & zero external dependencies
   â€¢   Safe no-op if localStorage unavailable
   â€¢   Public API exposed under TrueShade.Theme.*


Use Cases
   â€¢   Consistent dark / light theme switching across screens
   â€¢   Respect user’s OS preference unless explicitly overridden
   â€¢   Cross‑tab synchronization (storage event)


Installation

  1. Install the asset from the forge.
  2. Call the Initialize client action in your Layout's OnReady event.


Minimal CSS (place in Theme)

html[data-theme="dark"] {

  color-scheme: dark;

  background: #111;

  color: #eee;

}

html[data-theme="light"] {

  color-scheme: light;

  background: #fff;

  color: #111;

}


Public APIs

TrueShade.Theme.Initialize()

TrueShade.Theme.GetLayoutColorScheme()

TrueShade.Theme.GetStoredLayoutColorScheme()

TrueShade.Theme.SetLayoutColorScheme(ThemeId)

TrueShade.Theme.Dispose()


Behavior Details

Initialize(): Idempotent. Seeds localStorage with os-default if absent, applies theme, attaches listeners for OS changes + storage.

GetLayoutColorScheme(): Returns the effective mode; if stored is os-default it resolves to current OS (dark or light).

GetStoredLayoutColorScheme(): Returns literal stored string or null (before initialization seed).

SetLayoutColorScheme(mode): Accepts only os-default | dark | light; invalid logs console.error.

Dispose(): Removes listeners; does not delete stored preference.

Storage Key Format

Computed key: $OS_<ModuleName>$layout-theme


ModuleName is derived:

  1. First non-empty path segment (e.g. /Sales/Home → Sales)
  2. Else first hostname label (admin.example.com → admin)
  3. Empty fallback ⇒ plain layout-theme


DOM Contract

<html data-theme="dark|light"> is maintained. When user selects os-default the attribute auto tracks OS changes.


1.0.0

TrueShade Theme Controller

Lightweight JavaScript utility to manage Dark / Light / OS‑default theme in OutSystems apps by toggling the <html data-theme> attribute and persisting the user choice (per module) in localStorage.


Highlights
   â€¢   Modes: os-default | dark | light
   â€¢   Auto-follows OS dark mode when set to os-default
   â€¢   Per‑module key: $OS_<ModuleName>$layout-theme
   â€¢   Minimal DOM writes & zero external dependencies
   â€¢   Safe no-op if localStorage unavailable
   â€¢   Public API exposed under TrueShade.Theme.*


Use Cases
   â€¢   Consistent dark / light theme switching across screens
   â€¢   Respect user’s OS preference unless explicitly overridden
   â€¢   Cross‑tab synchronization (storage event)


Installation

  1. Install the asset from the forge.
  2. Call the Initialize client action in your Layout's OnReady event.


Minimal CSS (place in Theme)

html[data-theme="dark"] {

  color-scheme: dark;

  background: #111;

  color: #eee;

}

html[data-theme="light"] {

  color-scheme: light;

  background: #fff;

  color: #111;

}


Public APIs

TrueShade.Theme.Initialize()

TrueShade.Theme.GetLayoutColorScheme()

TrueShade.Theme.GetStoredLayoutColorScheme()

TrueShade.Theme.SetLayoutColorScheme(ThemeId)

TrueShade.Theme.Dispose()


Behavior Details

Initialize(): Idempotent. Seeds localStorage with os-default if absent, applies theme, attaches listeners for OS changes + storage.

GetLayoutColorScheme(): Returns the effective mode; if stored is os-default it resolves to current OS (dark or light).

GetStoredLayoutColorScheme(): Returns literal stored string or null (before initialization seed).

SetLayoutColorScheme(mode): Accepts only os-default | dark | light; invalid logs console.error.

Dispose(): Removes listeners; does not delete stored preference.

Storage Key Format

Computed key: $OS_<ModuleName>$layout-theme


ModuleName is derived:

  1. First non-empty path segment (e.g. /Sales/Home → Sales)
  2. Else first hostname label (admin.example.com → admin)
  3. Empty fallback ⇒ plain layout-theme


DOM Contract

<html data-theme="dark|light"> is maintained. When user selects os-default the attribute auto tracks OS changes.