8.1 KiB
| title | aliases | tags | sources | created | updated | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Figma Code Connect — Skill Workflow (.figma.ts templates) |
|
|
|
2026-05-15 | 2026-05-15 |
Figma Code Connect — Skill Workflow
Step-by-step process for creating .figma.ts template files that map Figma components to code snippets using the Figma MCP server skill.
Covers template files only (
.figma.tsusing MCP tools). Parser-based files (.figma.tsxwithfigma.connect()via CLI) are a separate approach.
Prerequisites
- Figma MCP tools available (e.g.
get_code_connect_suggestions) — verify before starting - Component published to a Figma team library (unpublished = stop)
- Organization or Enterprise plan (not Free/Pro)
- Figma URL must include
node-idquery param - Add
@figma/code-connect/figma-typestotsconfig.json:{ "compilerOptions": { "types": ["@figma/code-connect/figma-types"] } }
6-Step Workflow
Step 1 — Parse the Figma URL
Extract fileKey and nodeId:
| URL format | fileKey | nodeId |
|---|---|---|
figma.com/design/:fileKey/:name?node-id=X-Y |
:fileKey |
X-Y → X:Y |
figma.com/file/:fileKey/:name?node-id=X-Y |
:fileKey |
X-Y → X:Y |
Branch URL with :branchKey |
use :branchKey |
from node-id param |
Always convert hyphens to colons in nodeId: 1234-5678 → 1234:5678
Step 2 — Discover Unmapped Components
Call get_code_connect_suggestions with fileKey, nodeId, excludeMappingPrompt: true.
- "No published components found" → tell user to publish first, stop
- "All already connected" → inform user, stop
- Normal response → extract
mainComponentNodeIdper component; use these (not the original URL node) for all subsequent steps. Repeat Steps 3–6 for each component.
Step 3 — Fetch Component Properties
Call get_context_for_code_connect with fileKey, resolved nodeId, clientFrameworks, clientLanguages.
Property types returned:
| Type | Description |
|---|---|
| TEXT | Text content (labels, placeholders) |
| BOOLEAN | Toggle (show/hide, disabled) |
| VARIANT | Enum options (size, state) |
| INSTANCE_SWAP | Swappable nested instance (icon) |
| SLOT | Freeform content region |
Step 4 — Identify the Code Component
- Check
figma.config.jsonforpaths/importPaths - Search codebase in
src/components/,components/,lib/ui/,app/components/ - Compare props interface vs Figma properties from Step 3
- Confirm with user before writing the template
Step 5 — Create the Template File
File location: alongside existing .figma.ts/.figma.tsx files, named ComponentName.figma.ts
Template structure
// url=https://www.figma.com/file/{fileKey}/{fileName}?node-id={nodeId}
// source={path to code component}
// component={component name}
import figma from 'figma'
const instance = figma.selectedInstance
// property extractions...
export default {
example: figma.code`<Component ... />`,
imports: ['import { Component } from "..."'],
id: 'component-name',
metadata: { nestable: true, props: {} }
}
Property mapping methods
| Figma Type | Method | Notes |
|---|---|---|
| TEXT | instance.getString('Name') |
Returns string |
| BOOLEAN | instance.getBoolean('Name', { true: ..., false: ... }) |
Mapping optional |
| VARIANT | instance.getEnum('Name', { 'FigmaVal': 'codeVal' }) |
Must map ALL values |
| INSTANCE_SWAP | instance.getInstanceSwap('Name') |
Returns InstanceHandle | null |
| SLOT | instance.getSlot('Name') |
Returns ResultSection[] | undefined |
| Child layer | instance.findInstance('LayerName') |
No component property |
| Text layer | instance.findText('LayerName').textContent |
Named text layer |
VARIANT exhaustive mapping (critical)
Every value from get_context_for_code_connect must appear in getEnum. Unmapped value → silent undefined:
// Correct — all 4 values mapped
const status = instance.getEnum('Status', {
'Success': 'success',
'Error': 'error',
'Warning': 'warning',
'Info': 'info',
})
Interpolation rules
| Value type | Wrapping |
|---|---|
String (getString, getEnum, textContent) |
Quotes: variant="${variant}" |
Instance snippet (executeTemplate().example) |
Braces: icon={${iconCode}} |
Slot sections (getSlot()) |
Directly in template: `<X>${content}</X>` |
| Boolean bare prop | Conditional: ${disabled ? 'disabled' : ''} |
Instance swap pattern
const icon = instance.getInstanceSwap('Icon')
let iconCode
if (icon && icon.type === 'INSTANCE') { // type check required — findInstance returns ErrorHandle on failure
iconCode = icon.executeTemplate().example
}
SelectorOptions for findInstance/findText
// Target inside a nested instance (stop at boundary by default)
instance.findInstance('child', { traverseInstances: true })
// Disambiguate duplicate layer names
instance.findInstance('child', { traverseInstances: true, path: ['ParentLayer'] })
Step 6 — Validate
Read back the file and check:
- Every Figma property from Step 3 is covered
- All emitted attributes exist in the code component's
Propsinterface (never invent props) - No hardcoded children — INSTANCE_SWAP and slots use dynamic APIs
- INSTANCE_SWAP uses
getInstanceSwap(), notgetSlot(); SLOT usesgetSlot(), notgetInstanceSwap() type === 'INSTANCE'check present before everyexecuteTemplate()call
Key Takeaways
- 6 steps: parse URL → discover unmapped → fetch properties → identify code component → write template → validate
- VARIANT coverage is mandatory — every enum value must be in the mapping; missing = silent
undefined - Never string-concatenate
ResultSection[]— interpolate insidefigma.code`...`tagged templates hasCodeConnect()guard is wrong — always callexecuteTemplate()directly aftertype === 'INSTANCE'checkgetSlot()≠getInstanceSwap()— SLOT type usesgetSlot(), INSTANCE_SWAP usesgetInstanceSwap(); they are not interchangeable- Never hardcode child content — always resolve dynamically via
executeTemplate(), omit if no Code Connect exists findInstance()returns ErrorHandle (truthy) on failure, not null — always addtype === 'INSTANCE'guard- Confirm code component match with user before writing the template (Step 4)
Quick API Reference
instance.* methods
| Method | Returns |
|---|---|
getString(prop) |
string |
getBoolean(prop, mapping?) |
boolean | any |
getEnum(prop, mapping) |
any |
getInstanceSwap(prop) |
InstanceHandle | null |
getSlot(prop) |
ResultSection[] | undefined |
findInstance(name, opts?) |
InstanceHandle | ErrorHandle |
findText(name, opts?) |
TextHandle | ErrorHandle |
findConnectedInstance(id, opts?) |
InstanceHandle | ErrorHandle |
findConnectedInstances(fn, opts?) |
InstanceHandle[] |
findLayers(fn, opts?) |
(InstanceHandle | TextHandle)[] |
InstanceHandle methods
| Method | Returns |
|---|---|
executeTemplate() |
{ example: ResultSection[], metadata: Metadata } |
hasCodeConnect() |
boolean (avoid as a guard — see pitfalls) |
codeConnectId() |
string | null |
Related Articles
- wiki/claude-code/figma-mcp-code-connect — higher-level overview: CodeConnectSnippet wrapper, CLI vs MCP mappings
- wiki/claude-code/figma-mcp-skills — all 8 Figma MCP skills including
figma-code-connect-components - wiki/claude-code/figma-mcp-setup — enable Figma MCP server in Claude Code
- wiki/claude-code/figma-skill-build-screens — building/updating Figma screens from design system
- wiki/claude-code/figma-mcp-guide — Figma MCP server overview and capabilities
Sources
raw/Skill Code Connect Developer Docs.md— Figma Developer Docs, Code Connect skill reference