Plasmic Studio Guide
This guide describes the Plasmic Studio design tool and its core concepts.
If you prefer a more concrete primer to Plasmic in the context of an actual project, check out the Tour of the TodoMVC Plasmic project.
Building products is complex. On product teams, design and engineering most frequently collaborate around a handoff process. Today, this is a messy process, with multiple rounds of back and forth and many questions being raised. Designers spend significant time in design tools crafting high-fidelity vector drawings; however, vector drawing tools do not nudge designers towards thinking critically through the different states and contexts they must design for, to make proper use of the design system, and to be considerate of feasibility of implementation; doing so requires a lot of explicit effort and discipline. Developers take these drawings and recreate the intent of the designer from scratch, by hand, using code. Inevitably, many things fall through the cracks. Designers spend further time working with developers on finding and fixing these issues, or they reconcile the quirks of the actual production implementation back into their design files to be on the same page as the real product. Ultimately both sources of truth are almost never in sync, and it takes a lot of repeated manual effort from both sides to stay close to each other.
We see this as a collaboration problem and believe that better tooling can make a difference.
Plasmic is a design tool to bridge the gap between design and engineering by enabling a designer-controlled single source of truth for visuals that ship in the final product, while allowing engineers to add just the logic/data/behavior needed to take the designs into production. Unlike a one-time code export, we allow the designer to continue iterating on the design, and have those new changes be seamlessly reflected in generated code without discarding the work developers have done.
To learn more about the motivation and rationale, please see Plasmic Background.
- Focus on design-engineering collaboration. Streamlining and automating handoff enables consistency between design and production, helps communicate advanced layout and interactions, and empowers designers to impact the product without needing developers as translators. Plasmic lets you have a single source of truth across design and engineering.
- Focus on high-fidelity design. You can start with your familiar freeform design tool functionality that is critical to exploratory design, but access the tools and concepts needed to refine your designs for production and make your design system scale. You can represent component states, compose components together, design across different contexts (such as screen size, platform, locale, theme, dark mode, etc.), manage design tokens (color, etc.), all while using a full-featured layout engine that ensures your designs are appropriate for production.
- A general vector drawing tool. While you can absolutely draw screens from scratch in Plasmic, we’re not aiming to be a full Figma replacement. Instead, we will make it easy for you to import your design assets and exploratory designs from other best-of-breed tools such as Figma, Sketch, and Illustrator.
- An end-to-end app builder. Our goal is to help product teams consisting of designers and developers. While designers will be responsible for how components look, developers will be attaching component behaviors and data storage to Plasmic-generated UI by writing conventional code.
- A traditional codegen tool, which typically import from vector drawing tools and spit out code. A fundamental issue is that the source tool cannot represent various concepts needed for UIs that go into production (states, composition, layout, style abstractions, etc.). These tools often make a best guess as to the intent of the designer, but are typically far short of the mark because vector drawing tools are just too far apart from production code. At best, these tools provide a rough starting point that developers then heavily edit and mold into a real product. And, ultimately, the code generation is a one-time affair; once the developers have edited the generated code, you cannot generate code (mostly for updated visual design) again without blowing away the developers’ changes, severely limiting the design tool’s applicability in a product that requires ongoing iteration.
- An IDE UI builder. These focus on implementation rather than design, typically assuming a highly technical user (developer). They generally do not encourage the fast and flexible exploratory design that is the strength of most vector design tools. Users are expected to specify in the editor how the UI integrates with the code, such as specifying event handler callbacks or data bindings within the context of the production codebase.
A project is a “file” containing designs, analogous to a Figma file, Sketch file, etc. You can share projects, inviting other people as editors or commenters.
- Components, or reusable chunks of UI, similar to symbols in Sketch or components in Figma. We describe these in detail below.
- Reusable styles including tokens and mixins. We describe these in detail below.
- Arena — A canvas or workspace, analogous to “pages” in Figma/Sketch. This is where artboards are laid out. A project has multiple arenas you can switch between. All arenas in the same project share the same set of components and reusable styles.
- Artboard — Where the drawing happens. Unlike Figma/Sketch, you can only draw in artboards, not in the space between artboards. An artboard can either be used as a scratch pad, or for editing the master instance of your components. The artboard can also be independently sized (width/height) and placed anywhere in the arena.
The Studio UI has majorly five sections - the top toolbar, the canvas, the left bar, the right bar, and the component panel.
The canvas is the large area in the middle of the Studio UI showing the arena you’re currently viewing.
The left bar contains a few tabs:
- Tree shows the structure of artboards (and the component in it) in your arena, similar to the layers panel in other tools. A key difference is that the ordering is reversed from how layers work in other tools; we go top-down rather than bottom-up, so the elements lower on the list will draw on top of elements higher on the list.
- Gallery shows the components you have built, as well as some basic building blocks you can use in your designs.
- Assets shows the reusable styles defined in the project.
The right bar contains info about what you’ve currently selected. It shows the properties of the selected element or artboard for you to inspect/edit.
The floating components panel is shown whenever your selection is within a component artboard.
A component is a reusable chunk of UI, similar to symbols in Sketch or components in Figma. You can have small components like Buttons or Icons, large components for a whole Screen or Webpage, and things in between such as Login Form, Tweet, etc. You can have many instances of any component.
A component is built up of a tree of elements, similar to layers in other tools. These are either primitive elements like boxes, text elements, or input fields, or instances of other components. A component always has exactly one root element, usually a box containing other elements.
As an example, a ProfileCard component containing a picture and name side by side might be structured as follows. It has a root box that’s a horizontal stack, which arranges an image and a text element side by side.
Once you have built a Component, you can add instances of that component in other artboards anywhere you can add normal elements. You can thus compose instances of smaller Components into larger and more complex Components. Below, we drop in three instances of the ProfileCard into a new artboard.
Wherever you have an instance of a component, you can double-click on it to drill into editing the component master in Spotlight Mode. You can thus edit any component master in-place, with a spotlight shown on that component. This is in contrast to needing to navigate to the component master’s specific physical location in other design tools.
Below we introduce the core concepts in Plasmic that pertain to components.
A component can have multiple variants that represent different states. For example, a Button component might have Small, Medium, and Large variants, and also Primary, Secondary, and Danger variants.
All user-defined variants are organized into variant groups. For example, you might have a variant group called “Size” containing variants Small, Medium, and Large, as well as a variant group called “Type” containing variants Primary, Secondary, and Danger.
All components also have a base variant that defines its default appearance. You can see the organization in the floating Component Panel, which is where you can create and delete variant groups and variants.
By default, variant groups are single-choice groups, so your button can be either Primary or Secondary but not both. Variants in any group are also optional—your instances of Button can leave “Type” unset, so is neither Primary/Secondary; in that case, the Button will simply be displaying its “base” state.
The non-base variants hold style settings that override styles in the base variant. By default a variant inherits all the styles of the base variant. For instance, your Button’s Large variant might inherit all the same styles from of the Button’s base variant, but override only the font size of the button text. If you later make the Button rounded (in the base variant), your Large Button also becomes rounded.
This is also what lets you see a Button in a combination of variants. For instance, you can view a Button whose Size is Large and Type is Primary. Again, each variant only overrides specific styles, so Large overrides the font size, and Primary overrides the background color and text color.
We recommend that you put most of the Component styles in the base variant, and only put necessary override styles in the other variants; this allows you to share as much style as possible between the different variants of your component.
To make style changes to a specific variant, simply click on the desired variant in the Component Panel. The selected variant will light up in red, indicating that you are now recording changes for that variant. As you make changes in the right panel, a blue dot next to a style setting will indicate that it’s defined in the current variant, overriding the base variant. You can clear the override by right-clicking it and choosing Remove Style. To stop making style changes to a variant and go back to the base variant, simply select the base variant again in the Component Panel.
So far, we’ve said that variants contain style settings, but in fact they also hold other settings:
Visibility—whether the node is rendered at all or omitted in a variant. For instance, a sidebar in a screen design might be visible only on the desktop variant and not a mobile variant. Visibility can be toggled with the eye icon in the Tree in the left sidebar.
If your component contains other component instances, then what variant(s) you want active on those other components. For example, a ProfileCard component might contain a Button instance for following/unfollowing a user, which we want to enable or disable depending on whether the current user is following the person in the ProfileCard. The ProfileCard then might have two variants — a “following” variant, where the Button instance has the “Type = Disabled” variant activated, and a “not-following” variant, where the Button instance has the “Type = Primary” variant activated.
You may want to define variants that correspond to common interactions, such as the hovered and pressed states of a Button. You can create special interaction variants for some fundamental interaction types, including Hovered, Pressed, Disabled, and Focused. They’re special because when you switch into Preview mode (by pressing the Play button in the top toolbar), you can immediately see these variants in action by interacting with your design.
You can also define these to be any combination of the above. For instance, you may want an interaction variant for when the button is “Hovered and Not Disabled.”
Interaction variants are always defined as nested under some other (normal) variant.
Slots are sections of a component that are meant for component instances to fill in with arbitrary content. They are like “holes” in a component.
For example, a Button component may be responsible for the border / background / font color / etc., but it can be customized with any button content. One Button can say “OK,” another “Cancel,” and another an icon alongside “Submit.”
Usually slots have default content. The Button’s default slot might just be “Button text here.”
Components can also have multiple slots. A Card component might have a header slot and a body slot.
To create a slot, right-click any element and choose “Convert To Slot.” This exposes a slot on the component that element belongs to. The element you converted becomes the default content for the slot.
Then, wherever you have an instance of that component, you can directly manipulate the slot contents. For instance, you can simply double click on the Button’s text to type in something else.
If you don’t override the slot, it will always reflect the current default contents (i.e. it reflects the update you made to the default contents).
Slots can be compared with overrides in other design tools, but with key differences:
- Slots are a way to override that is officially blessed by the component author. This is critical to allowing a design system to scale and to informing component consumers what are appropriate ways to override a component.
- Slots allow flexible component composition. It should be easy to plug in arbitrary content into a slot, including multiple other elements and components.
Props are settings to configure on a component instance. Variant groups and slots are types of props on a component.
Besides variants and slots, you can take any element in the component and expose its non-style attributes as props. For instance, if you have a “Labeled Input” component containing an input textbox, you can expose the “placeholder” as a prop of the “Labeled Input” component, so that each instance of “Labeled Input” can specify its own placeholder.
Components are one powerful tool to achieve reuse and maintain consistency throughout your design. Style tokens and style mixins are another such set of tools, focused on styling and appearance.
Style tokens are simple reusable named style values. Currently, Plasmic supports defining color tokens. For instance, rather than using the color “#0070e0” everywhere, you can define it as your app’s “Accent Color” and use that anywhere you can apply a color (background colors, text colors, gradient colors, etc.).
You can define these as-you-go anywhere you have a color picker, or you can create them directly from the Assets tab in the left sidebar. The Assets tab is also where you can see a list of all your existing color tokens.
Then whenever you pull up the color picker, you can select a color token that you’ve previously defined.
Color tokens can be defined in terms of other tokens. For instance, you may have a base color scale that defines tokens “Blue-100” through “Blue-900.” Then on top of that, you may define a color token “Accent Color” as always being “Blue-700.” If you later adjust your color scale, Accent Color is similarly updated.
Style mixins are reusable bundles of styles. Whereas a token is just a simple value (such as a specific color like “#0070e0” without caring if it’s used as a background color, text color, gradient color, etc.), a mixins might specify that:
- the background color is “#0070e0”
- the padding is 10px all around
- the drop shadow should be dark gray, be offset 10px and have a 10px blur
Basically, most of the usual style settings available to you in the right sidebar can be stored into a mixin.
Mixins are listed in the Assets tab in the left sidebar.
You can create new ones there, or if you already have styles defined on some element, you can extract some or all of those styles into a mixin.
Then you can apply this on any (non-component) element, and it will adopt that visual appearance.
All the styles that come from a mixin have a green dot indicator in the right panel.
The layout system in Plasmic is designed to be uncompromising, so that you can express a much richer set of layouts than what is available in today’s design tool auto-layout features, while remaining confident that these can be directly represented in the target platform.
Layout is accomplished using boxes, a basic element type. It acts as a container and can hold other elements as children. A box can be a free box whose children have free-floating positioning (“absolute positioning” in CSS terminology), or automatically lay them out in a horizontal or vertical stack. You can insert these from the Gallery, or draw these using the top toolbar icons:
In free boxes, you can specify whether the item is anchored to the top/left of its parent (the default), or perhaps the top/right. You can even anchor to both the left and right of the parent, so that resizing the parent resizes the child in a way that maintains fixed left/right margin widths. This is similar to Constraint Layout in other design tools.
A horizontal or vertical stack arranges its children in a row or column automatically. This frees designers up from worrying about maintaining exact placement, and is how most UIs in production behave.
Stacks can specify a default gap between their items. Stacks also have the ability to wrap, and as such can specify a cross-axis gap (e.g., a row gap for a horizontal stack).
Stacks can also specify padding (as shown above), which is how much they nudge their children inward from their own border.
When you draw a box (including stacks) onto the screen around some other elements, those elements will become nested as children in the newly drawn box.
You can also take a box and press “Shift+A” to cycle through the auto-layout configurations. If it’s currently a free container, we’ll guess what is the desired stack layout (horizontal/vertical) from the positions of the items in the box.
Although by default stacks imply the children are auto laid out, you can in fact set any particular stack child to be free-floating, which is occasionally useful for placing the red badge in this example:
Depending on the layout, an element’s size (width and/or height) can be:
- Fixed size, e.g. 32px
- Hugging or “tightly wrapping” its own content. For instance, a button should always wrap its own text content with constant padding.
- Stretching to fill its parent. For instance, a Nav Menu component should always stretch to span the width of the screen.
You can mix these on different axes—while the Nav Menu should stretch horizontally, perhaps it should be hug its content vertically.
You can also set more advanced layout configurations using min and max sizing constraints. For instance, you want a button to hug its text, but also want a minimum width and/or maximum width (forcing the text to wrap or truncate).
An artboard is just a view of a component. You can have many artboards viewing a component, each one viewing it in a different variant.
However, when you create a brand new artboard, it actually isn’t associated with a component at all. It’s just a blank canvas for you to draw on—a scratch space. You can convert a scratch artboard into a component, after which the artboard will be a view of that component. Do so by selecting an artboard and clicking this button in the right sidebar.
When an artboard is a view of a component, we call that a bound artboard. You are directly editing the component master in that artboard. (You can also edit the component master anywhere there is an instance of a component—double-clicking instances drills into editing the master in Spotlight Mode.)
Earlier we describe variants, which are always specific to a component. For instance, the primary variant of a button.
However, if you want to re-theme the entire app, such as adding a “Dark mode,” you probably want to change many components together.
Global variants are similar to normal (component-specific) variants, in that components can appear differently in different global variants. However, global variants themselves are global to the entire project, meaning that any component can have specific style settings defined under a single “Dark mode” variant.
Besides dark mode, there are many other use cases for global variants, where you want many components in the app to change together:
- platform—web vs. iOS vs. Android
- screen size—mobile vs. desktop
- palette—light mode vs. dark mode vs. sepia vs. high-contrast dark
- locale—LTR vs. RTL languages
- brand—Facebook vs. Instagram vs. WhatsApp, or Material vs. Cloud Material
- configurations—Gmail roomy vs. dense
For instance, a global variant for iOS vs. Android might switch over the look of many components:
This is a particularly powerful feature for designing robust design system components that allow product designers to view their designs across multiple contexts.
To create and manage global variants, select into any component to bring up the floating variants panel, and in the bottom section you’ll see the global variants listed, with the ability to create more.
You can then set any artboard to render its contents in the context of some global variant(s).
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. Here’s an example project showing exactly that, along with a short explainer video:
A big part of becoming efficient at working in Plasmic is learning its keyboard shortcuts. Press Shift-? on your keyboard to bring up the shortcut keys quick reference.
We can’t wait to see what you create with Plasmic.