Switching global variables doesn't work

I spent two days trying to implement changing global variables via a code component. I’m changing the theme from dark to light.

Is something broken in Plasmic?

Hello @se.belobrov

Changing global variants (like a dark/light theme) via a code component in Plasmic does work—but it requires some setup outside of just the component itself.

Plasmic doesn’t currently allow you to toggle global variants entirely within Studio or a standalone code component. Instead, you’ll need to:

  • Manage the variant state in your app (e.g. using React context)
  • Pass that state to the PlasmicRootProvider via the globalVariants prop

I’ll walk you through a working setup. But first, I recommend reviewing:

  1. Create a React context to manage the variant
// context/GlobalVariantContext.tsx
import { createContext, useContext, useState } from "react";

interface GlobalVariantContextType {
  isDarkMode: boolean;
  toggleDarkMode: () => void;
}

const defaultContextValue: GlobalVariantContextType = {
  isDarkMode: false,
  toggleDarkMode: () => {},
};

const GlobalVariantContext = createContext<GlobalVariantContextType>(defaultContextValue);

export function GlobalVariantProvider({ children }: { children: React.ReactNode }) {
  const [isDarkMode, setIsDarkMode] = useState(false);
  const toggleDarkMode = () => setIsDarkMode((prev) => !prev);

  return (
    <GlobalVariantContext.Provider value={{ isDarkMode, toggleDarkMode }}>
      {children}
    </GlobalVariantContext.Provider>
  );
}

export const useGlobalVariant = () => {
  const context = useContext(GlobalVariantContext);
  return context || defaultContextValue; // fallback inside Studio preview
};
  1. Wrap your loader app with GlobalVariantProvider
// pages/[[...catchall]].tsx
export default function PlasmicLoaderPage(props: {
  plasmicData?: ComponentRenderData;
  queryCache?: Record<string, unknown>;
}) {
  const { plasmicData } = props;

  if (!plasmicData || plasmicData.entryCompMetas.length === 0) {
    return <Error statusCode={404} />;
  }

  const pageMeta = plasmicData.entryCompMetas[0];

  return (
    <GlobalVariantProvider>
      <PlasmicWrapper>
        <PlasmicComponent component={pageMeta.displayName} />
      </PlasmicWrapper>
    </GlobalVariantProvider>
  );
}
  1. Pass the variant into PlasmicRootProvider
// components/PlasmicWrapper.tsx
function PlasmicWrapper({ children }: { children: React.ReactNode }) {
  const { isDarkMode } = useGlobalVariant();

  return (
    <PlasmicRootProvider
      loader={PLASMIC}
      globalVariants={[{ name: "Theme", value: isDarkMode ? "dark" : "light" }]}
    >
      {children}
    </PlasmicRootProvider>
  );
}

Make sure the global variant name ("Theme") and values ("dark" / "light") match exactly with what you defined in Plasmic Studio (they’re case-sensitive).

  1. Create a code component to toggle the theme
// components/DarkModeToggle.tsx
import { useGlobalVariant } from "../context/GlobalVariantContext";

export function DarkModeToggle() {
  const { isDarkMode, toggleDarkMode } = useGlobalVariant();

  return (
    <button onClick={toggleDarkMode}>
      {isDarkMode ? "Switch to Light Mode" : "Switch to Dark Mode"}
    </button>
  );
}

  1. Register your component with Plasmic
// plasmic-init.ts
PLASMIC.registerComponent(DarkModeToggle, {
  name: "DarkModeToggle",
  props: {},
});

Now you can drag the DarkModeToggle into any page in Studio.