Writing code components for use with Plasmic

Often, you can just directly register your usual code components as-is for use with Plasmic. This works great for any design systems components or presentational components you already have.

But if you are tailoring components explicitly to be used with Plasmic, you can make them better integrated with the Studio by using these additional APIs or following these tips.

Allow positioning and styling via className prop

If your code component renders some DOM elements, then you should allow your Studio users to have some control over its styling — for example, setting its width and height, its alignment in a flex container, etc.

To do so, your component should expose a className prop that is passed onto the root DOM element:

components/MyComponent.tsx
Copy
function MyComponent({ className }: { className?: string }) {
return <div className={className}>{/* ... other stuff goes here */}</div>;
}

This only styles the root element (instead of any arbitrary element in your code component). Usually that makes sense — your component should already come with its own styles and layout, and usually you only want to allow positioning-related styles to be set on the root element.

Detect if your component is rendering in Plasmic Studio

You might want to disable some functionality inside the component when it is used inside Plasmic Studio artboards — for example, disable slow scroll animations, videos, or certain compute-heavy effects.

For that reason, we provide a React context PlasmicCanvasContext whose value is true only when the component is rendering in the Editor.

Sometimes, it makes sense to even expose a prop for your component that Plasmic users can toggle to turn certain features on and off:

Communicate between components via React Contexts

Your code components can communicate with each other through React Contexts. One common pattern is for one code component to fetch and provide some data via a React Context, and for other code components to read from that Context and display a piece of that data.

For example, here we have a component ProductProvider that fetches and provides data for a product, and components like ProductTitle or ProductPrice that renders the product title and price:

components/ProductParts.tsx
Copy
const ProductContext = React.createContext<Product | undefined>(undefined);
function ProductProvider({ slug, children }: { slug: string; children: ReactNode }) {
const data = useFetchProductData(props.slug);
return <ProductContext.Provider value={data}>{children}</ProductContext.Provider>;
}
function ProductTitle({ className }: { className?: string }) {
const product = React.useContext(ProductContext);
// Use a default string in case this component is used outside of ProductContext
const title = product?.title ?? 'Product Title';
return <div className={className}>{title}</div>;
}
function ProductPrice({ className }: { className?: string }) {
const product = React.useContext(ProductContext);
const price = product?.price ?? 100;
return <div className={className}>{formatCurrency(price)}</div>;
}

Repeating slot content for each element of a list

One important use of code components is for fetching and using dynamic data from your own data store. Often, you will fetch a collection of something, and would like to repeat the slot content once for every element in the collection. For example, you might have fetched a list of products, and want to render something once per product.

To do this, use the repeatedElement() function. This ensures an editing experience in Plasmic Studio where the user can select and make edits just the first replica of the slot contents.

The repeatedElement function expects two parameters: a boolean isPrimary and a React node elt:

  • isPrimary: Indicates the primary copy to be edited in the editor (usually the first copy). Should be true for only one of the copies.
  • elt: The element to be cloned. If the value provided is not a valid ReactElement, the original value is returned. Otherwise, React.cloneElement is used to clone the element, applying required tweaks to elements from the Editor.

Learn more about incorporating dynamic data into your Plasmic designs.

Applying global themes / contexts to code components

Since your code components are rendered on your host page, it will have access to whatever css or React contexts that exist on the host page. So if your code components require contexts to work, simply make sure they are provided when rendering PlamsicCanvasHost:

Copy
<ThemeContext.Provider>
<PlasmicCanvasHost />
</ThemeContext.Provider>

Any component instances used in your Plasmic designs will have access to the context as per usual.

Custom behaviors (attachments)

You may want your code components to be used as wrapper components (like animations, effects, behaviors, etc). To do that, you can register them as “attachments”, and they will be available on the right panel of Studio, in the Custom behaviors section.

Notice that these components can have any number of props, but can only have a single slot prop called “children”.

For example,

Copy
// Registering MyAnimation as an attachment
registerComponent(MyAnimation, {
name: 'My Animation',
isAttachment: true,
props: {
maxAngleX: 'number',
maxAngleY: 'number',
color: 'string',
children: 'slot'
}
});

Data-fetching code components

Continue reading onto the next section to learn how to fetch data from your own data backends in a way that works with SSR/SSG.

Was this page helpful?

Give feedback on this page