Creating Component Variants Programmatically in Figma: A Complete Guide
Use the createComponentWithVariants helper in skills/figma-generate-library/scripts/createComponentWithVariants.js to automatically generate Cartesian product combinations of variant axes, instantiate individual ComponentNode objects for each combination, and combine them into a ComponentSetNode using figma.combineAsVariants.
The figma/mcp-server-guide repository provides a production-ready automation script that eliminates manual component duplication through the Figma Plugin API. This approach ensures consistent naming conventions and proper variant structure while following design-system best practices that mandate establishing variant axes before adding non-variant properties.
The Eight-Step Variant Generation Workflow
The createComponentWithVariants function orchestrates the entire component lifecycle through a deterministic eight-step process. Each step targets specific Figma Plugin API methods to ensure thread-safe node creation and proper canvas organization.
Step 1: Page Preparation
The function begins by guaranteeing the target page is active before any node creation occurs. It calls await figma.setCurrentPageAsync(page) to prevent race conditions that could scatter components across multiple pages. This awaitable API call is critical for maintaining deterministic behavior in async plugin environments.
Step 2: Cartesian Product Calculation
The helper computes every possible combination of variant values using a local cartesianProduct() utility (lines 44‑48). This pure-JavaScript implementation leverages Array.reduce paired with flatMap to efficiently generate the matrix of property combinations without external dependencies.
Step 3: Component Instantiation
For each combination in the Cartesian product, the script calls figma.createComponent() and formats the node name according to Figma’s variant naming convention ("Property=Value, Property2=Value2"). This occurs at line 53 in the source file. The function applies all base visual properties—including width, height, fills, cornerRadius, and auto-layout settings—before the combination step, ensuring each variant inherits the correct geometry.
Step 4: Metadata Tagging
To enable later discovery and cleanup operations, each component receives persistent metadata through comp.setPluginData() (lines 88‑94). The script stores a deterministic dsb_key and an optional runId parameter, allowing external scripts to query and manage generated nodes reliably using getPluginData().
Step 5: Variant Combination
The script transforms the flat array of components into a unified ComponentSetNode by invoking figma.combineAsVariants(components, page) at line 100. After this API call, Figma automatically recognizes the shared variant axes across all children, enabling the variant picker interface in the design panel.
Step 6: Grid Layout
To prevent variants from stacking at coordinates (0, 0), the function iterates over componentSet.children (lines 13‑18) and calculates grid positions based on the size of the last variant axis. The algorithm applies a configurable GRID_GAP constant to ensure readable spacing between matrix elements.
Step 7: Parent Resizing
The component set container expands to encompass all children plus padding using componentSet.resize() (lines 24‑27). The script uses a PADDING constant of 40 pixels to prevent canvas clipping and ensure the variant set displays fully within the viewport.
Step 8: Canvas Positioning
Finally, the function positions the completed set at x = 480, y = 80 (lines 30‑31) to avoid overlapping with existing file content. This safe-zone placement strategy keeps programmatically generated components organized and distinct from manually created design elements.
Critical Implementation Details
The Variants-First Rule
According to the design-system documentation in skills/figma-use/references/working-with-design-systems/wwds-components--creating.md, you must define all variant axes before adding non-variant properties such as text overrides, boolean operations, or instance-swaps. Adding these properties after variant creation risks destructive changes to existing component instances throughout your design files.
Visual Property Timing
All geometry and styling attributes—including comp.resize(), comp.fills, comp.layoutMode, and comp.padding* values—must be applied prior to the combineAsVariants call. Properties set after combination do not propagate correctly to the individual variant nodes within the set.
Line-Specific Architecture
- Lines 44‑48: Cartesian product generation using functional array methods
- Line 53: Component naming with Figma’s variant property syntax
- Lines 88‑94: Plugin data persistence for traceability
- Line 100: The atomic combination operation that creates the
ComponentSetNode
Code Example: Creating a Button Component Set
The following example generates a Button component set with two variant axes: Size (Small, Medium, Large) and Style (Primary, Ghost).
// Generate a 3×2 matrix of button variants
await createComponentWithVariants(
{
name: "Button",
variantAxes: {
Size: ["Small", "Medium", "Large"],
Style: ["Primary", "Ghost"]
},
baseProps: {
width: 120,
height: 40,
radius: 8,
fills: [{ type: "SOLID", color: { r: 0.0, g: 0.5, b: 1.0 } }],
layoutMode: "NONE"
},
page: figma.root.pages[0]
},
"run-12345"
);
What this execution accomplishes:
- Calculates six total combinations (3 × 2) of Size and Style values
- Creates six individual
ComponentNodeobjects with the specified blue fill and 8px corner radius - Assigns variant-compliant names like
"Size=Small, Style=Primary" - Tags each node with the
runId"run-12345"for later bulk operations - Combines nodes into a
ComponentSetNodeand arranges them in a 2-column grid - Positions the final set at coordinates
(480, 80)with appropriate padding
Source File Reference
| File Path | Purpose |
|---|---|
skills/figma-generate-library/scripts/createComponentWithVariants.js |
Core implementation containing the eight-step workflow and cartesianProduct helper |
skills/figma-use/references/working-with-design-systems/wwds-components--creating.md |
Design-system guidelines emphasizing the "variants first" architecture |
skills/figma-use/references/component-patterns.md |
Figma component-set model documentation and naming conventions |
skills/figma-use/references/gotchas.md |
Common pitfalls including stacked variants and missing plugin data |
Summary
- Use
createComponentWithVariantsfromskills/figma-generate-library/scripts/createComponentWithVariants.jsto automate variant generation through Cartesian product mathematics. - Always apply visual properties before combination to ensure attributes persist in the final
ComponentSetNode. - Tag components with
setPluginDatausing the built-indsb_keyand optionalrunIdparameters for reliable future discovery and cleanup. - Follow the variants-first rule by defining all axes before adding text, boolean, or instance-swap properties to prevent instance corruption.
- Position variants in a grid immediately after
figma.combineAsVariantsto maintain organized canvas layouts and prevent overlapping nodes.
Frequently Asked Questions
What is the createComponentWithVariants function?
createComponentWithVariants is a helper utility in the Figma MCP Server Guide that automates the creation of variant component sets. It accepts a configuration object defining variantAxes, baseProps, and a target page, then executes an eight-step workflow to generate, combine, and position the resulting ComponentSetNode on the Figma canvas.
Why must visual properties be set before calling combineAsVariants?
Figma’s combineAsVariants API captures the current state of each ComponentNode at the moment of combination. Properties applied after this call—such as fills, strokes, or auto-layout settings—do not automatically propagate to the variants within the set. Setting comp.fills, comp.resize(), and geometry attributes before line 100 ensures every variant inherits the correct visual specification.
How does the script determine grid layout for variants?
The grid algorithm defaults to using the size of the last variant axis as the column count. It iterates through componentSet.children (lines 13‑18), calculating x and y coordinates based on index position modulo the column count, multiplied by a GRID_GAP constant. This creates a readable matrix layout rather than stacking all variants at the origin point.
Can I use metadata tags to find these components later?
Yes. The script stores a deterministic dsb_key and your optional runId parameter using comp.setPluginData() (lines 88‑94). You can later query these values using node.getPluginData("dsb_key") or node.getPluginData("runId") to identify, select, or delete programmatically generated components without affecting manually created design elements.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →