appsmithorg/appsmith · error · Error

onThemeChange expects a function as parameter

Error message

onThemeChange expects a function as parameter

What it means

Thrown by window.appsmith.onThemeChange() in the WDS (Widget Design System) Custom Widget iframe. This WDS variant exposes a theme object (the current Appsmith theme: colors, borderRadius, spacing, typography) and onThemeChange subscribes a callback that is invoked immediately with the current theme and again on every theme switch. Only present in the WDS widget; the legacy CustomWidget does not expose it.

Source

Thrown at app/client/src/widgets/wds/WDSCustomWidget/component/customWidgetscript.js:205

        styleElement.setAttribute("data-appsmith-theme", "");
        styleElement.textContent = event.cssTokens;
        document.head.appendChild(styleElement);
      }
    }
  });

  if (!window.appsmith) {
    // Define appsmith global object
    Object.defineProperty(window, "appsmith", {
      configurable: false,
      writable: false,
      value: {
        mode: "",
        theme: {},
        onThemeChange: (fn) => {
          if (typeof fn !== "function") {
            throw new Error("onThemeChange expects a function as parameter");
          }

          themeSubscribers.push(fn);
          fn(window.appsmith.theme);

          return () => {
            // Unsubscribe from theme changes
            const index = themeSubscribers.indexOf(fn);

            if (index > -1) {
              themeSubscribers.splice(index, 1);
            }
          };
        },
        onModelChange: (fn) => {
          if (typeof fn !== "function") {
            throw new Error("onModelChange expects a function as parameter");
          }

View on GitHub (pinned to 8cd9021c24)

Solutions

  1. Pass a function reference: appsmith.onThemeChange(applyTheme).
  2. Use an inline arrow: appsmith.onThemeChange((theme) => document.documentElement.style.setProperty('--app-bg', theme.colors.backgroundColor)).
  3. Keep the returned unsubscribe function and call it when the iframe is torn down to prevent leaks across re-renders.

Example fix

// before
appsmith.onThemeChange(handleTheme()); // invokes, passes undefined

// after
appsmith.onThemeChange(handleTheme); // passes the function reference
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof themeHandler !== 'function') {
  throw new TypeError('onThemeChange expects a function');
}
const off = appsmith.onThemeChange(themeHandler);

Type guard

const isCallable = (v) => typeof v === 'function';

// usage
if (isCallable(applyTheme)) appsmith.onThemeChange(applyTheme);

Try / catch

try {
  const off = appsmith.onThemeChange(applyTheme);
} catch (e) {
  console.error('onThemeChange registration failed:', e.message);
}

Prevention

When it happens

Trigger: Calling appsmith.onThemeChange(undefined), appsmith.onThemeChange(null), appsmith.onThemeChange('dark'), appsmith.onThemeChange({onChange:fn}), or appsmith.onThemeChange() from the WDS widget's iframe script.

Common situations: Porting legacy CustomWidget code (which has no onThemeChange) into a WDS widget and referencing a handler that is not yet defined; passing a config object instead of the handler; forgetting that themeSubscribers stores raw function references for later invocation.

Related errors


AI-assisted analysis of appsmithorg/appsmith@8cd9021c24 (2026-08-12). Data as JSON: /api/errors/09965bd568e6082a. Report an issue: GitHub.