| name | figma-connect-component |
| description | Generate Figma Code Connect mappings that link React components to their Figma counterparts. Use when a component exists in code and needs a Code Connect file so Figma shows real code snippets in Dev Mode. Also triggers on phrases like "connect this component to Figma", "generate Code Connect", "publish to Figma", "add figma.connect for this component", "link this to Figma Dev Mode". |
| argument-hint | <figma-url> [<component-file-path>] |
| user-invocable | true |
Generate Figma Code Connect for React Components
When to Use This Skill
User provides a Figma component URL (or component name) and wants to generate the Code Connect mapping for it.
Required Inputs
- Figma component identifier (one of):
- Full URL:
https://figma.com/design/{fileKey}/{fileName}?node-id={nodeId}
- File key + node ID:
fileKey: abc123, nodeId: 45:67
- Evidence file path:
.temp/figma-explore/{component}.json or .temp/figma-connect-shadcn/{component}.json
- Component name (will search for URL in project files)
- Code component folder path (e.g.,
src/components/Button/Button.tsx)
Execution Steps
1. Gather Figma Component Data
Option A: Evidence File Provided (Preferred)
If an evidence file from figma-explore is provided (e.g., .temp/figma-explore/{component}.json):
- Read the JSON file directly
- Extract:
id (node ID), name, variants, variantProperties, componentPropertyDefinitions
- The file contains all the variant names and values needed for Code Connect
Example evidence file structure:
{
"id": "16:1234",
"name": "Button",
"type": "COMPONENT_SET",
"variants": [
{ "name": "Type=Primary, Size=Small", "id": "16:1235" },
{ "name": "Type=Primary, Size=Large", "id": "16:1236" }
],
"variantProperties": {
"Type": ["Primary", "Secondary", "Ghost"],
"Size": ["Small", "Medium", "Large"]
},
"componentPropertyDefinitions": {
"Label": { "type": "TEXT", "defaultValue": "Button" },
"Show Icon": { "type": "BOOLEAN", "defaultValue": false }
}
}
Option B: URL/Node ID Provided (MCP Fallback)
If only a Figma URL or node ID is provided:
- Search for existing evidence files in
.temp/figma-explore/ or .temp/figma-connect-shadcn/ that match the component name
- If not found, use MCP tools:
- Call
mcp_figma_get_metadata with nodeId and fileKey
- Call
mcp_figma_get_design_context with nodeId and fileKey
2. Discover Figma URL (if needed)
If no URL or evidence file provided, search for it:
- Check
{ComponentFolder}/README.md for "Figma Source" section
- Check
specs/**/tasks.md for component-to-Figma mapping tables
- Check
.temp/figma-explore/figma-components-index.json or .temp/figma-connect-shadcn/figma-components-index.json for matching component names
- Check prior conversation context for file key
3. Read Code Component and Inline the Mapping Contract
- Read the specified component file — identify exports, props interface, component name
- If
.temp/design-components/{component-name}/proposed-api.md exists, read it and inline the prop-to-Figma mapping table into your working context. Do not reference this file by path during generation — the full mapping must be in active context so no property is guessed or missed.
- Cross-check: every prop in the React interface should have a corresponding Figma source in the table. Props with no Figma source (e.g.,
className, id) are omitted from Code Connect.
4. Generate Mapping
- Declare each prop as a top-level
const using figma.selectedInstance.* methods
- Build the example using the
figma.code tagged template literal
- Add appropriate imports
5. Write Code Connect File
- Output to:
{ComponentFolder}/{ComponentName}.figma.ts
- Raw file content only—no markdown fences
6. Update README with Mapping Diagram
If {ComponentFolder}/README.md exists, ensure it has a Design-to-Code Mapping section with a mermaid flowchart at the top showing the Figma-to-React property relationships.
Diagram format:
flowchart LR
subgraph Figma["Figma Variants"]
FProp1["PropertyName1"]
FProp2["PropertyName2"]
end
subgraph React["React Props"]
RProp1["propName1"]
RProp2["propName2"]
end
FProp1 -->|"Value1 → 'code1'<br>Value2 → 'code2'"| RProp1
FProp2 -->|"mapping description"| RProp2
style Figma fill:#f3e8ff,stroke:#9333ea
style React fill:#dbeafe,stroke:#3b82f6
Placement: The mermaid diagram should be placed immediately after the ## Design-to-Code Mapping heading, before any tables.
Example README structure:
## Design-to-Code Mapping
```mermaid
flowchart LR
subgraph Figma["Figma Variants"]
FSize["Size"]
FType["Type"]
end
subgraph React["React Props"]
RSize["size"]
RVariant["variant"]
end
FSize -->|"Small → 'sm'<br>Medium → 'md'<br>Large → 'lg'"| RSize
FType -->|"Primary → 'primary'<br>Secondary → 'secondary'"| RVariant
style Figma fill:#f3e8ff,stroke:#9333ea
style React fill:#dbeafe,stroke:#3b82f6
` ` `
### Variant Mappings
| Figma Variant | Figma Value | React Prop | React Value |
...
Rules for the diagram:
- Include all mapped variant properties (from
getEnum() calls)
- Include boolean properties that map to React props
- Show value transformations on the arrows (e.g.,
"Small → 'sm'")
- Use
<br> for multiple value mappings on one arrow
- Exclude pseudo-states (hover, focus, pressed) from the diagram
- Use purple styling for Figma subgraph, blue for React subgraph
Rules
Use Exact Figma Property Names
Critical: Code Connect requires the EXACT property names as they appear in Figma.
- Get exact names from evidence files or
get_metadata output
- Property names like
ButtonType, Type, Size must match EXACTLY (case-sensitive)
- The
get_design_context MCP tool normalizes to camelCase — do NOT use those names
- Property names are case-sensitive:
Size ≠ size
Example from metadata:
name="ButtonType=Responsive, Type=Primary, Size=Small"
Use in Code Connect:
const size = instance.getEnum('Size', { ... })
const variant = instance.getEnum('Type', { ... })
Only Use Real Figma Properties
Map based on what exists in Figma:
- Variant/enum properties →
instance.getEnum()
- Boolean properties →
instance.getBoolean()
- Text/string properties →
instance.getString()
- Instance swap properties →
instance.getInstanceSwap()
- Slot properties →
instance.getSlot()
- Nested layer by name →
instance.findInstance(), instance.findText()
- Nested by Code Connect ID →
instance.findConnectedInstance(), instance.findConnectedInstances()
Never invent properties that don't exist in Figma.
Value Conventions
- Drop pseudo-state variants:
hover, pressed, focused, state, interaction
- Map Figma Title Case to code:
Primary → 'primary', Small → 'sm'
- Normalize boolean variants: "Yes"/"No", "True"/"False", "On"/"Off" →
true/false
Prop Rendering in the Template
The figma.code tag does not auto-format values — you control the output syntax:
| Prop type | Template syntax | Output |
|---|
| String enum | size="${size}" | size="small" |
| Boolean | disabled={${disabled}} | disabled={false} or omit via renderProp |
| Instance/JSX | icon={${icon}} | icon={<Icon />} |
| String children | >${label}< | >Click me< |
| Unknown/mixed type | ${figma.helpers.react.renderProp('size', size)} | handles all types correctly |
Never use {${varName}} for string enum values — it outputs size={small} (looks like an undefined JS variable). Use "${size}" for known strings.
When the prop type could be a string, boolean, instance, or undefined, use figma.helpers.react.renderProp instead of hardcoding the syntax.
Critical Constraint: No JavaScript Expressions in Templates
figma.code snippets are not executed — they are rendered as static display strings.
Never use:
figma.code`${hasIcon ? iconSnippet : null}`
figma.code`${'<Icon />' + iconSnippet}`
Ternary conditionals on snippet values (ResultSection[]) are fine. String concatenation is not.
API Reference
Instance Access
import figma from 'figma'
const instance = figma.selectedInstance
const instance = figma.currentLayer
Property Methods
const label = instance.getString('Label')
const disabled = instance.getBoolean('Disabled')
const icon = instance.getBoolean('Has Icon', {
true: instance.getInstanceSwap('Icon')?.executeTemplate().example,
false: undefined,
})
const size = instance.getEnum('Size', {
Small: 'sm',
Medium: 'md',
Large: 'lg',
})
const iconInstance = instance.getInstanceSwap('Icon')
const iconSnippet = iconInstance?.executeTemplate().example
const slotContent = instance.getSlot('Slot Name')
const raw = instance.getPropertyValue('Prop Name')
Finding Nested Layers
const icon = instance.findInstance('Icon Layer Name')
const iconSnippet = icon.executeTemplate().example
const btn = instance.findConnectedInstance('button')
const btnSnippet = btn.executeTemplate().example
const items = instance.findConnectedInstances(node => node.codeConnectId() === 'list-item')
const itemSnippets = items.map(i => i.executeTemplate().example)
const layers = instance.findLayers(node => node instanceof TextHandle)
const text = instance.findText('Label Layer')
const textContent = text.textContent
const nested = instance.findInstance('Icon', {
path: ['Parent Layer'],
traverseInstances: true,
})
figma.code Template
Use figma.code as a tagged template literal. Interpolate property values and nested snippets:
export default {
example: figma.code`
<Button size="${size}" disabled={${disabled}}>
${label}
</Button>
`,
}
You can compose nested figma.code blocks:
const label = figma.code`<label>${labelContent}</label>`
export default {
example: figma.code`
<Button>
${iconSnippet}
${label}
</Button>
`,
}
figma.helpers.react
Use these when prop type is dynamic or you want automatic correct formatting:
figma.helpers.react.renderProp('disabled', true)
figma.helpers.react.renderProp('disabled', false)
figma.helpers.react.renderProp('label', 'Click me')
figma.helpers.react.renderProp('count', 42)
figma.helpers.react.renderProp('icon', iconSnippet)
figma.helpers.react.renderChildren('Hello')
figma.helpers.react.renderChildren(snippets)
figma.helpers.react.jsxElement('<CustomIcon />')
figma.helpers.react.identifier('myVariable')
figma.helpers.react.function('() => alert("hi")')
figma.helpers.react.object({ color: 'red' })
figma.helpers.react.templateString('Hello ${name}')
figma.helpers.react.reactComponent('MyComponent')
figma.helpers.react.array([1, 2, 3])
figma.helpers.react.stringifyObject({ a: 1 })
Export Format
export default {
example: figma.code`...`,
imports: string[],
id: string,
metadata?: {
nestable?: boolean,
props?: Record<string, any>,
},
}
Metadata Comments (top of file)
Complete Example
import figma from 'figma'
const instance = figma.selectedInstance
const variant = instance.getEnum('Variant', {
Primary: 'primary',
Secondary: 'secondary',
})
const size = instance.getEnum('Size', {
Small: 'sm',
Medium: 'md',
Large: 'lg',
})
const disabled = instance.getBoolean('Disabled')
const label = instance.getString('Label')
const iconInstance = instance.getInstanceSwap('Icon')
const iconSnippet = iconInstance?.executeTemplate().example
export default {
id: 'Button',
imports: ['import { Button } from "@/components/Button"'],
example: figma.code`
<Button variant="${variant}" size="${size}" disabled={${disabled}} icon={${iconSnippet}}>
${label}
</Button>
`,
metadata: { nestable: true },
}
Example with renderProp (mixed/unknown prop types)
import figma from 'figma'
const instance = figma.selectedInstance
const slotNo = instance.getEnum('Slot No.', {
'1 Slot': '1 Slot',
'2 Slots': '2 Slots',
})
const header = instance.getInstanceSwap('Header Slot')?.executeTemplate().example
const main = instance.getInstanceSwap('Main Slot')?.executeTemplate().example
export default {
id: 'Card',
imports: ['import { Card } from "@/components/Card"'],
example: figma.code`<Card slotNo="${slotNo}" headerSlot={${header}} mainSlot={${main}} />`,
metadata: { nestable: true },
}
Example with nested connected instances
import figma from 'figma'
const instance = figma.selectedInstance
const items = instance.findConnectedInstances(node => node.codeConnectId() === 'tab-item')
const itemSnippets = items.map(i => i.executeTemplate().example)
export default {
id: 'TabGroup',
imports: ['import { TabGroup, Tab } from "@/components/Tabs"'],
example: figma.code`
<TabGroup>
${figma.helpers.react.renderChildren(itemSnippets)}
</TabGroup>
`,
metadata: { nestable: false },
}
What NOT to Do
- Don't use
get_design_context property names. MCP normalizes them to camelCase. The actual Figma property names are Title Case with spaces (e.g., Has Icon, ButtonType, Size). Use get_metadata output or the raw variant names from evidence files.
- Don't invent properties that don't exist in Figma. If
proposed-api.md lists a prop like className that has no Figma source, omit it from Code Connect entirely.
- Don't use
{${varName}} for string enums. It outputs size={small} — looks like an undefined JS variable. Use "${varName}" for known strings, or figma.helpers.react.renderProp for mixed types.
- Don't use the old
figma.connect() API. The new template API uses figma.selectedInstance.* and export default { ... }.
- Don't concatenate snippet values.
'<Tag />' + snippetVar breaks rendering. Always compose inside figma.code\...``.
- Don't map pseudo-states.
hover, focus, pressed, active Figma variants have no corresponding props — exclude them.
- Don't reference
proposed-api.md by path during generation. The mapping contract must be inlined into your working context in Step 3.
Output
Write raw file content only — no markdown fences, no explanations.
File location: {ComponentFolder}/{ComponentName}.figma.ts
Example: src/components/inline-edit/EditableText/EditableText.figma.ts
File must be immediately usable with npm run figma:publish.