Global variants

Earlier we described variants, which are always specific to a component or an element. For instance, the primary variant of a button.

Global variants are similar to normal (component-specific) variants, in that components can appear differently in different global variants. However, global variants apply across the entire project, meaning that any component can have specific style settings defined under a single “Dark mode” variant.

Dark mode global variant

Global variants use cases

Besides dark mode, there are many other use cases for global variants, where you want many components in the app to change together:

  • Screen size -— mobile vs. desktop
  • Color pallette — light/dark mode, sepia, high-contrast etc.
  • Translations — different languages, LTR vs. RTL layouts
  • Configurable layouts -— a closest example would be Gmail’s roomy vs. dense mode
  • Vendor-specific brand — different branding colors for different vendors

For instance, a global variant for iOS-styled look vs. Google’s Material UI might switch over the look of many components:

How to create a global variant

To create and manage a global variant:

  1. Select any element in a component or a page

  2. Navigate to the Page (or Component) Data tab, and scroll to the bottom to find the “Global Variants” section.

Global variants section
  1. You’ll see the global variants listed, with the ability to create more. Click the + button to create a new global variant group.

  2. Let’s call it “Text Direction”, and create two variants in this group: “RTL” and “LTR”.

Global variants text direction
  1. LTR would not need any changes because it would be the same as the base variant, so let’s select the RTL variant and apply the changes to all the components that are present on this page:
  1. Now, go back to your page, and switch to the RTL variant — you’ll see that the text direction has changed:
Global variants text direction

Responsive design using screen variants

There’s a special global variant group called “Screen” variants, built in to all projects. These are treated specially because they can specify min and max viewport widths at which they kick in. For instance, if you’re doing mobile-first design but want to make adjustments for the desktop, you can create a screen variant called “Desktop” that activates on devices over 300px wide. Then, whenever you have an artboard that is over 300px, this Desktop variant will be automatically shown by default.

To learn more, see responsive design using screen variants.

Switching between global variants during runtime

While Plasmic Studio doesn’t support switching global variants based on user interactions out of the box, you can implement this functionality by setting up your app host to manage the variant state.

Prerequisites

This example requires setting up an app host connected to Plasmic Studio and basic knowledge of React concepts like context, hooks, and components.

As an example, we’ll build a dark mode switcher that toggles between light and dark themes. You can inspect the resulting demo and source code in this repository, or follow a step by step guide:

  1. Create a global variant group in Plasmic Studio called Theme, and two global variants named light and dark.

In order to do that go to any page or a component, and in the right sidebar select the Page (or Component) Data tab. Then scroll to the bottom to find the Global Variants section and hit the + button to create a new global variant group:

Global variants in Plasmic Studio
  1. Create a React context to manage the global variant state:
Copy
// contexts/GlobalVariantContext.tsx
// (optional) persist theme preference in cookies
import { getCookie, setCookie } from 'cookies-next';
import React from 'react';
// Cookie name for theme preference
const THEME_COOKIE_NAME = 'plasmic-theme';
interface GlobalVariantContextType {
isDarkMode: boolean;
toggleDarkMode: () => void;
}
const defaultContextValue: GlobalVariantContextType = {
isDarkMode: true, // Default to dark mode if not set
toggleDarkMode: () => {}
};
const GlobalVariantContext = React.createContext<GlobalVariantContextType>(defaultContextValue);
export function GlobalVariantProvider({ children }: { children: React.ReactNode }) {
// Load theme preference from cookie on mount
const [isDarkMode, setIsDarkMode] = React.useState(false);
React.useEffect(() => {
const savedTheme = getCookie(THEME_COOKIE_NAME);
setIsDarkMode(!savedTheme || savedTheme === 'dark');
}, []);
const toggleDarkMode = () => {
setIsDarkMode((prev) => {
// Save the new value to cookies
setCookie(THEME_COOKIE_NAME, !prev ? 'dark' : 'light');
return !prev;
});
};
return (
<GlobalVariantContext.Provider value={{ isDarkMode, toggleDarkMode }}>{children}</GlobalVariantContext.Provider>
);
}
export const useGlobalVariant = () => {
const context = React.useContext(GlobalVariantContext);
return context || defaultContextValue; // fallback inside Studio preview
};
  1. Pass the name and the active value of the variant that you want to change into the PlasmicRootProvider:
Copy
// components/PlasmicWrapper.tsx
import { PlasmicRootProvider } from '@plasmicapp/loader-nextjs';
import { useGlobalVariant } from '@/contexts/GlobalVariantContext';
type PlasmicWrapperProps = React.ComponentProps<typeof PlasmicRootProvider>;
export function PlasmicWrapper(props: PlasmicWrapperProps) {
const { children, ...rest } = props;
const { isDarkMode } = useGlobalVariant();
return (
<PlasmicRootProvider {...rest} globalVariants={[{ name: 'Theme', value: isDarkMode ? 'dark' : 'light' }]}>
{children}
</PlasmicRootProvider>
);
}
  1. Wrap your loader app with GlobalVariantProvider:
Copy
// 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. Create a wrapper component to pass the current state and actions to the Studio:
Copy
// components/DarkModeToggleWrapper.tsx
import React from 'react';
import { DataProvider } from '@plasmicapp/loader-nextjs';
import { useGlobalVariant } from '@/contexts/GlobalVariantContext';
interface DarkModeToggleWrapperProps {
children?: React.ReactNode;
}
interface DarkModeToggleWrapperActions {
toggleTheme(): void;
}
const DarkModeToggleWrapperBase = ({ children }: DarkModeToggleWrapperProps, ref: React.Ref<unknown>) => {
const { isDarkMode, toggleDarkMode } = useGlobalVariant();
React.useImperativeHandle(ref, () => ({
toggleTheme: toggleDarkMode
}));
return (
<DataProvider name="theme" data={{ isDarkMode }}>
{children}
</DataProvider>
);
};
export const DarkModeToggleWrapper = React.forwardRef<DarkModeToggleWrapperActions, DarkModeToggleWrapperProps>(
DarkModeToggleWrapperBase
);
  1. Register your code component to make it available in Plasmic Studio:
Copy
// plasmic-init.ts
PLASMIC.registerComponent(DarkModeToggleWrapper, {
name: 'DarkModeToggleWrapper',
props: {
children: 'slot'
},
providesData: true,
refActions: {
toggleTheme: {
argTypes: [],
displayName: 'Toggle dark mode',
description: 'Toggles between light and dark mode'
}
}
});
  1. Use the DarkModeToggleWrapper component in Studio to wrap the UI element that would act as a toggle (a Button, for example)

  2. Use your Theme global variant to style the button in the light and dark modes. Alternatively you can use the isDarkMode prop passed to the component.

  3. Add an onChange interaction to the UI element to call the Toggle dark mode element action.

Global variants in Plasmic Studio

Is this page helpful?

NoYes