diff --git a/figma-power/POWER.md b/figma-power/POWER.md index 52c28cb..23a694a 100644 --- a/figma-power/POWER.md +++ b/figma-power/POWER.md @@ -1,8 +1,8 @@ --- name: "figma" displayName: "Figma" -description: "Comprehensive Figma integration for implementing designs as production-ready code, connecting Figma components to code via Code Connect, and generating project-specific design system rules. Use when implementing UI from Figma files, connecting components to code, creating design system rules, or when user provides Figma URLs." -keywords: ["figma", "design", "implement", "component", "ui", "code generation", "design system", "code connect", "mapping", "design to code", "rules", "guidelines", "implement design", "implement component", "generate code", "connect component", "design rules", "build design"] +description: "Comprehensive Figma integration for building and updating designs, screens, components, design systems, diagrams, FigJam boards, and Slides directly in Figma via the Plugin API, plus SwiftUI translation and Code Connect mapping. Use when creating or editing anything in a Figma, FigJam, or Slides file from code or a description, building a design system, generating diagrams, or connecting components to code." +keywords: ["figma", "figjam", "slides", "design", "component", "design system", "variables", "tokens", "ui", "use_figma", "plugin api", "$fig", "create in figma", "build in figma", "write to figma", "push to figma", "code to design", "generate design", "build screen", "build page", "build component", "component library", "theming", "diagram", "flowchart", "sequence diagram", "erd", "gantt", "mermaid", "new figma file", "create file", "swiftui", "swift", "ios", "code connect", "component mapping"] author: "Figma" --- @@ -10,22 +10,35 @@ author: "Figma" ## Overview -This Power provides three core capabilities for working with Figma: +This Power builds and edits content directly in Figma via the Plugin API, and bridges code and design. Capabilities: -1. **Implement Design** — Translate Figma designs into production-ready code with pixel-perfect accuracy -2. **Code Connect Components** — Connect Figma design components to their code implementations using Code Connect -3. **Create Design System Rules** — Generate project-specific design system rules that guide consistent Figma-to-code workflows +### Plugin API — build & edit in Figma +1. **Use the Plugin API** — execute JavaScript in the Figma file context (via the `$fig` builder) to create/edit/read nodes, variables, components, auto-layout, and fills (`figma-use`; foundational, load it alongside the others) +2. **Generate designs from code** — build or update pages, screens, modals, and multi-section views from code or a description using design-system tokens (`figma-generate-design`) +3. **Build design systems** — create variables/tokens, component libraries, variant sets, and theming from a codebase (`figma-generate-library`) +4. **FigJam** — create and edit FigJam boards (stickies, connectors, sections, tables) via the Plugin API (`figma-use-figjam`) +5. **Slides** — create and edit Figma Slides via the Plugin API (`figma-use-slides`) +6. **Create a new file** — create a blank design, FigJam, or Slides file (`figma-create-new-file`) + +### Diagrams +7. **Generate diagrams** — create FigJam diagrams from Mermaid syntax: flowcharts, sequence, ERD, state, gantt, architecture (`figma-generate-diagram`) + +### Code ↔ Design +8. **SwiftUI ↔ Figma** — translate a Figma design into SwiftUI, or push SwiftUI views/tokens back into Figma (`figma-swiftui`) +9. **Code Connect** — create and maintain Code Connect templates mapping Figma components to code (`code-connect-components`) ## When to Use This Power Activate this Power when the user: -- Provides a Figma URL and wants to implement the design as code -- Mentions: implement design, generate code, implement component, build Figma design, build components matching Figma specs -- Mentions: code connect, connect this component to code, map this component, link component to code, create code connect mapping -- Mentions: create design system rules, generate rules for my project, set up design rules, customize design system guidelines -- Wants to establish mappings between Figma designs and code implementations -- Wants to establish project-specific conventions for Figma-to-code workflows +- Wants to create, edit, or delete anything in a Figma, FigJam, or Slides file — nodes, variables, components, auto-layout, fills, tokens +- Says: write to Figma, create in Figma from code, push page/screen/component to Figma, build a landing page/modal/dialog/panel in Figma +- Wants to build or update a design system, component library, variables/tokens, or theming (light/dark) +- Wants to create a new blank Figma, FigJam, or Slides file +- Wants to create a diagram — flowchart, sequence, ERD, state machine, gantt, architecture — or mentions Mermaid +- Mentions Swift, SwiftUI, iOS, iPhone, or iPad in either direction (design → SwiftUI or SwiftUI → Figma) +- Mentions Code Connect, component mapping, or `.figma.ts` / `.figma.js` files +- Provides a Figma URL and wants to build on or modify the file ## Available MCP Tools @@ -33,72 +46,83 @@ The Figma MCP server provides these tools: | Tool | Description | |------|-------------| -| `get_design_context` | Fetches structured design data (layout, typography, colors, spacing, component structure) for a layer or selection | +| `use_figma` | Executes JavaScript against the Figma Plugin API in the file context (via the `$fig` builder) — create/edit/read nodes, variables, components, auto-layout, fills | +| `create_new_file` | Creates a new blank Figma design, FigJam, or Slides file | +| `generate_figma_design` | Converts UI descriptions or code into design layers in a Figma file | +| `generate_diagram` | Creates FigJam diagrams from Mermaid syntax (flowcharts, sequence, ERD, state, gantt) | +| `search_design_system` | Searches a design-system library for components, variables, and styles to reuse | +| `get_design_context` | Fetches structured design data (layout, typography, colors, spacing, component structure) for a selection | | `get_metadata` | Returns a sparse XML representation with basic layer properties like IDs, names, and dimensions | | `get_screenshot` | Captures a visual screenshot of a Figma selection to preserve layout fidelity | -| `get_variable_defs` | Retrieves variables and styles (colors, spacing, typography) from selections | +| `get_figjam` | Converts FigJam content to XML including metadata and node screenshots | | `get_code_connect_suggestions` | Detects and suggests Code Connect mappings between Figma and code components | -| `send_code_connect_mappings` | Confirms Code Connect mappings after suggestions are generated | -| `get_code_connect_map` | Maps Figma node IDs to corresponding code components in your codebase | -| `add_code_connect_map` | Establishes new mappings between Figma elements and code implementations | -| `create_design_system_rules` | Generates rule files that guide agents in translating designs to frontend code | -| `generate_figma_design` | Converts UI descriptions into design layers in Figma files | -| `get_figjam` | Converts FigJam diagrams to XML format including metadata and node screenshots | -| `generate_diagram` | Creates FigJam diagrams from Mermaid syntax (flowcharts, Gantt charts, etc.) | +| `upload_assets` | Uploads image assets into a Figma file | | `whoami` | Returns authenticated user identity and plan information | ## Steering -Load the appropriate workflow based on the user's intent: +Load the appropriate workflow based on the user's intent. `figma-use.md` is foundational — load it alongside any Plugin API write task: -- **Implementing a Figma design as code** → `readPowerSteering("figma", "implement-design.md")` -- **Connecting Figma components to code via Code Connect** → `readPowerSteering("figma", "code-connect-components.md")` -- **Creating design system rules for a project** → `readPowerSteering("figma", "create-design-system-rules.md")` +- **Executing Plugin API reads/writes in a Figma file** → `readPowerSteering("figma", "figma-use.md")` +- **Building or updating a page / screen / view from code or a description** → `readPowerSteering("figma", "figma-generate-design.md")` + `readPowerSteering("figma", "figma-use.md")` +- **Building or updating a design system, components, variables, or tokens** → `readPowerSteering("figma", "figma-generate-library.md")` + `readPowerSteering("figma", "figma-use.md")` +- **Working in FigJam via the Plugin API** → `readPowerSteering("figma", "figma-use-figjam.md")` + `readPowerSteering("figma", "figma-use.md")` +- **Working in Slides via the Plugin API** → `readPowerSteering("figma", "figma-use-slides.md")` + `readPowerSteering("figma", "figma-use.md")` +- **Creating a new blank Figma, FigJam, or Slides file** → `readPowerSteering("figma", "figma-create-new-file.md")` +- **Creating a FigJam diagram from Mermaid** → `readPowerSteering("figma", "figma-generate-diagram.md")` +- **Translating between SwiftUI and Figma** → `readPowerSteering("figma", "figma-swiftui.md")` (+ `readPowerSteering("figma", "figma-use.md")` for code → design) +- **Mapping Figma components to code via Code Connect** → `readPowerSteering("figma", "code-connect-components.md")` ## Prerequisites - Figma MCP server must be connected and accessible -- User must provide a Figma URL in the format: `https://figma.com/design/:fileKey/:fileName?node-id=1-2` -- Project should have an established design system or component library (preferred but not required) +- For file-specific work, the user should provide a Figma URL: `https://figma.com/design/:fileKey/:fileName?node-id=1-2` +- For build-from-code tasks, an established design system or component library improves fidelity (preferred but not required) ## Quick Usage Examples -### Implement a Design +### Build a screen from code + +User: "Take this settings page and build it in Figma." + +→ Load `figma-generate-design.md` + `figma-use.md`, discover design-system components/variables, then assemble the view section-by-section using tokens. + +### Build a design system -User: "Implement this Figma button: https://figma.com/design/kL9xQn2VwM8pYrTb4ZcHjF/DesignSystem?node-id=42-15" +User: "Create a component library with variables and light/dark theming from my codebase." -→ Load `implement-design.md` steering, then follow the 7-step workflow to fetch context, capture screenshot, download assets, translate to project conventions, and validate. +→ Load `figma-generate-library.md` + `figma-use.md`, then create variable collections, components with variants, and bind tokens. -### Connect Components via Code Connect +### Generate a diagram -User: "Connect this Figma button to my code: https://figma.com/design/kL9xQn2VwM8pYrTb4ZcHjF/DesignSystem?node-id=42-15" +User: "Draw a sequence diagram of our auth handshake in FigJam." -→ Load `code-connect-components.md` steering, then follow the 4-step workflow to get suggestions, scan codebase, present matches, and create mappings. +→ Load `figma-generate-diagram.md`, then produce valid Mermaid and call `generate_diagram`. -### Create Design System Rules +### SwiftUI ↔ Figma -User: "Create design system rules for my React project" +User: "Implement this Figma screen in SwiftUI." / "Push my SwiftUI view into Figma." -→ Load `create-design-system-rules.md` steering, then follow the 5-step workflow to run the tool, analyze codebase, generate rules, save to CLAUDE.md, and validate. +→ Load `figma-swiftui.md` (+ `figma-use.md` for the code → design direction). ## Troubleshooting ### Figma output is truncated -The design is too complex for a single response. Use `get_metadata` to get the node structure, then fetch specific nodes individually with `get_design_context`. +The design is too complex for a single response. Use `get_metadata` for the node structure, then fetch specific nodes with `get_design_context`. + +### Always load `figma-use` before `use_figma` + +`use_figma` calls fail in common, hard-to-debug ways without the Plugin API guidance. Load `figma-use.md` before any Plugin API write. ### Assets not loading -Verify the Figma MCP server's assets endpoint is accessible. The server serves assets at `localhost` URLs — use these directly without modification. Do not import new icon packages or create placeholders. +Verify the Figma MCP server's assets endpoint is accessible. The server serves assets at `localhost` URLs — use these directly. Do not import new icon packages or create placeholders. ### No published components found (Code Connect) -Code Connect only works with published components. The user needs to publish the component to a team library in Figma first. Code Connect is only available on Organization and Enterprise plans. +Code Connect only works with published components. Publish the component to a team library first. Code Connect is only available on Organization and Enterprise plans. ### Design token values differ from Figma -When project tokens differ from Figma values, prefer project tokens for consistency but adjust spacing/sizing to maintain visual fidelity. - -### Claude isn't following design system rules - -Make rules more specific and actionable. Add "IMPORTANT:" prefix to critical rules. Verify rules are saved in the correct configuration file and restart the IDE or MCP client to reload. +Prefer project tokens for consistency, but adjust spacing/sizing to maintain visual fidelity. diff --git a/figma-power/mcp.json b/figma-power/mcp.json index 4a9bcff..8978784 100644 --- a/figma-power/mcp.json +++ b/figma-power/mcp.json @@ -2,7 +2,10 @@ "mcpServers": { "figma": { "type": "http", - "url": "https://mcp.figma.com/mcp" + "url": "https://mcp.figma.com/mcp", + "headers": { + "X-Figma-Plugin-Bundle": "figquery@0.1.27" + } } } } diff --git a/figma-power/steering/code-connect-components.md b/figma-power/steering/code-connect-components.md index db43d65..8c850c2 100644 --- a/figma-power/steering/code-connect-components.md +++ b/figma-power/steering/code-connect-components.md @@ -1,323 +1,1827 @@ -# Code Connect Components +# Code Connect ## Overview -This skill helps you connect Figma design components to their corresponding code implementations using Figma's Code Connect feature. It analyzes the Figma design structure, searches your codebase for matching components, and establishes mappings that maintain design-code consistency. +Create Code Connect template files (`.figma.ts`) that map Figma components to code snippets. Given a Figma URL, follow the steps below to create a template. + +> **Note:** This project may also contain parser-based `.figma.tsx` files (using `figma.connect()`, published via CLI). This skill covers **templates files only** — `.figma.ts` files that use the MCP tools to fetch component context from Figma. ## Prerequisites -- Figma MCP server must be connected and accessible -- User must provide a Figma URL with node ID: `https://figma.com/design/:fileKey/:fileName?node-id=1-2` - - **IMPORTANT:** The Figma URL must include the `node-id` parameter. Code Connect mapping will fail without it. -- **IMPORTANT:** The Figma component must be published to a team library. Code Connect only works with published components or component sets. -- **IMPORTANT:** Code Connect is only available on Organization and Enterprise plans. -- Access to the project codebase for component scanning +- **Figma MCP server must be connected** — verify that Figma MCP tools (e.g., `get_code_connect_suggestions`) are available before proceeding. If not, guide the user to enable the Figma MCP server and restart their MCP client. +- **Components must be published** — Code Connect only works with components published to a Figma team library. If a component is not published, inform the user and stop. +- **Organization or Enterprise plan required** — Code Connect is not available on Free or Professional plans. +- **URL must include `node-id`** — the Figma URL must contain the `node-id` query parameter. +- **TypeScript types** — for editor autocomplete and type checking in `.figma.ts` files `@figma/code-connect/figma-types` must be added to `types` in `tsconfig.json`: + ```json + { + "compilerOptions": { + "types": ["@figma/code-connect/figma-types"] + } + } + ``` + +## Step 1: Parse the Figma URL + +Extract `fileKey` and `nodeId` from the URL: + +| 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` | +| `figma.com/design/:fileKey/branch/:branchKey/:name` | use `:branchKey` | from `node-id` param | + +Always convert `nodeId` hyphens to colons: `1234-5678` → `1234:5678`. + +**Worked example:** + +Given: `https://www.figma.com/design/QiEF6w564ggoW8ftcLvdcu/MyDesignSystem?node-id=4185-3778` +- `fileKey` = `QiEF6w564ggoW8ftcLvdcu` +- `nodeId` = `4185-3778` → `4185:3778` + +## Step 2: Discover Unmapped Components + +The user may provide a URL pointing to a frame, instance, or variant — not necessarily a component set or standalone component. Call the MCP tool `get_code_connect_suggestions` with: +- `fileKey` — from Step 1 +- `nodeId` — from Step 1 (colons format) +- `excludeMappingPrompt` — `true` (returns a lightweight list of unmapped components) + +This tool identifies published components in the selection that don't yet have Code Connect mappings. + +**Handle the response:** + +- **"No published components found in this selection"** — the node contains no published components. Inform the user they need to publish the component to a team library in Figma first, then stop. +- **"All component instances in this selection are already connected to code via Code Connect"** — everything is already mapped. Inform the user and stop. +- **Normal response with component list** — extract the `mainComponentNodeId` for each returned component. Use these resolved node IDs (not the original from the URL) for all subsequent steps. If multiple components are returned (e.g. the user selected a frame containing several different component instances), repeat Steps 3–6 for each one. + +## Step 3: Fetch Component Properties + +Call the MCP tool `get_context_for_code_connect` with: +- `fileKey` — from Step 1 +- `nodeId` — the resolved `mainComponentNodeId` from Step 2 +- `clientFrameworks` — determine from `figma.config.json` `parser` field (e.g. `"react"` → `["react"]`) +- `clientLanguages` — infer from project file extensions (e.g. TypeScript project → `["typescript"]`, JavaScript → `["javascript"]`) + +For multiple components, call the tool once per node ID. + +The response contains the Figma component's **property definitions** — note each property's name and type: +- **TEXT** — text content (labels, titles, placeholders) +- **BOOLEAN** — toggles (show/hide icon, disabled state) +- **VARIANT** — enum options (size, variant, state) +- **INSTANCE_SWAP** — swappable nested instances tied to a specific component (icon, avatar) +- **SLOT** — flexible content regions (freeform layout, mixed children); use `getSlot()` in templates (not the same as INSTANCE_SWAP) -## Required Workflow +Save this property list — you will use it in Step 5 to write the template. -**Follow these steps in order. Do not skip steps.** +## Step 4: Identify the Code Component -### Step 1: Get Code Connect Suggestions +If the user did not specify which code component to connect: -Call `get_code_connect_suggestions` to identify all unmapped components in a single operation. This tool automatically: +1. Check `figma.config.json` for `paths` and `importPaths` to find where components live +2. Search the codebase for a component matching the Figma component name. Check common directories (`src/components/`, `components/`, `lib/ui/`, `app/components/`) if `figma.config.json` doesn't specify paths +3. Read candidate files and compare their props interface against the Figma properties from Step 3 — look for matching variant types, size options, boolean flags, and slot props +4. If multiple candidates match, pick the one with the closest prop-interface match and explain your reasoning to the user +5. If no match is found, show the 2 closest candidates and ask the user to confirm or provide the correct path -- Fetches component info from the Figma scenegraph -- Identifies published components in the selection -- Checks existing Code Connect mappings and filters out already-connected components -- Returns component names, properties, and thumbnail images for each unmapped component +**Confirm with the user** before proceeding to Step 5. Present the match: which code component you found, where it lives, and why it matches (prop correspondence, naming, purpose). -Parse the URL to extract `fileKey` and `nodeId`, then call `get_code_connect_suggestions`. +Read `figma.config.json` for import path aliases — the `importPaths` section maps glob patterns to import specifiers, and the `paths` section maps those specifiers to directories. -**IMPORTANT:** When extracting the node ID from a Figma URL, convert the format: +Read the code component's source to understand its props interface — this informs how to map Figma properties to code props in Step 5. -- URL format uses hyphens: `node-id=1-2` -- Tool expects colons: `nodeId=1:2` +## Step 5: Create the Template File (.figma.ts) -**Parse the Figma URL:** +### File location -- URL format: `https://figma.com/design/:fileKey/:fileName?node-id=1-2` -- Extract file key: `:fileKey` (segment after `/design/`) -- Extract node ID: `1-2` from URL, then convert to `1:2` for the tool +Place the file alongside existing Code Connect templates (`.figma.tsx` or `.figma.ts` files). Check `figma.config.json` `include` patterns for the correct directory. Name it `ComponentName.figma.ts`. +### Template structure + +Every template file follows this structure: + +```ts +// url=https://www.figma.com/file/{fileKey}/{fileName}?node-id={nodeId} +// source={path to code component from Step 4} +// component={code component name from Step 4} +import figma from 'figma' +const instance = figma.selectedInstance + +// Extract properties from the Figma component (see property mapping below) +// ... + +export default { + example: figma.code``, // Required: code snippet + imports: ['import { Component } from "..."'], // Optional: import statements + id: 'component-name', // Required: unique identifier + metadata: { // Optional + nestable: true, // true = inline in parent, false = show as pill + props: {} // data accessible to parent templates + } +} ``` -get_code_connect_suggestions(fileKey=":fileKey", nodeId="1:2") + +### Property mapping + +Use the property list from Step 3 to extract values. For each Figma property type, use the corresponding method: + +| Figma Property Type | Template Method | When to Use | +|---|---|---| +| TEXT | `instance.getString('Name')` | Labels, titles, placeholder text | +| BOOLEAN | `instance.getBoolean('Name', { true: ..., false: ... })` | Toggle visibility, conditional props | +| VARIANT | `instance.getEnum('Name', { 'FigmaVal': 'codeVal' })` | Size, variant, state enums | +| INSTANCE_SWAP | `instance.getInstanceSwap('Name')` | Swapped instance for a fixed component slot (then `hasCodeConnect()` / `executeTemplate()`) - do not confuse with the SLOT property below | +| SLOT | `instance.getSlot('Name')` | Freeform slot content only when the Figma property type is **SLOT** +| (child layer) | `instance.findInstance('LayerName')` | Named child instances without a property | +| (text layer) | `instance.findText('LayerName')` → `.textContent` | Text content from named layers | + +**TEXT** — get the string value directly: +```ts +const label = instance.getString('Label') ``` -**Handle the response:** +**VARIANT** — map Figma enum values to code values: +```ts +const variant = instance.getEnum('Variant', { + 'Primary': 'primary', + 'Secondary': 'secondary', +}) + +const size = instance.getEnum('Size', { + 'Small': 'sm', + 'Medium': 'md', + 'Large': 'lg', +}) +``` + +**BOOLEAN** — simple boolean or mapped to values: +```ts +// Simple boolean +const disabled = instance.getBoolean('Disabled') + +// Mapped to code values (e.g. when the code prop is an enum, not a boolean) +const size = instance.getBoolean('Show Label', { true: 'large', false: 'small' }) +``` + +**Map Figma properties to code props where there's a valid correspondence.** Figma properties and code props don't always line up 1:1 — some Figma properties map directly (by name, or via the API methods above), others have no code equivalent. Where a mapping exists, use it; where none fits, omit the Figma property rather than invent a code prop. Never emit an attribute whose name doesn't appear in the code component's `Props` interface. + +### Exhaustive variant handling + +When a VARIANT property has multiple possible values, the `getEnum` mapping **must list every value** returned by `get_context_for_code_connect`. Don't omit values — an unmapped value silently returns `undefined`, producing broken output. + +```ts +// WRONG — omits 'Warning', which will render as undefined +const status = instance.getEnum('Status', { + 'Success': 'success', + 'Error': 'error', +}) + +// CORRECT — every value is mapped +const status = instance.getEnum('Status', { + 'Success': 'success', + 'Error': 'error', + 'Warning': 'warning', + 'Info': 'info', +}) +``` + +When **two or more VARIANT properties combine** to produce different code output, generate exhaustive conditional branches. For example, 2 variants × 2 values = 4 branches: + +```ts +const type = instance.getEnum('Type', { 'Filled': 'filled', 'Outlined': 'outlined' }) +const status = instance.getEnum('Status', { 'Success': 'success', 'Error': 'error' }) + +let colorClass +if (type === 'filled' && status === 'success') { + colorClass = 'bg-green-500 text-white' +} else if (type === 'filled' && status === 'error') { + colorClass = 'bg-red-500 text-white' +} else if (type === 'outlined' && status === 'success') { + colorClass = 'bg-transparent border-green-500' +} else if (type === 'outlined' && status === 'error') { + colorClass = 'bg-transparent border-red-500' +} +``` + +If the combinations produce **repetitive** output (e.g., `Size` doesn't change the snippet structure — it's just passed through as a prop), a single `getEnum` mapping per variant is sufficient — no need for cross-product branches. + +**INSTANCE_SWAP** — access swappable component instances: +```ts +const icon = instance.getInstanceSwap('Icon') +let iconCode +if (icon && icon.type === 'INSTANCE') { + iconCode = icon.executeTemplate().example +} +``` + +**SLOT** — `getSlot(propName)` is only valid when the Figma component property reported in Step 3 has type **`SLOT`**. Do not use `getSlot()` for **INSTANCE_SWAP** properties (those use `getInstanceSwap()`). Slots are explicit “content regions” in the component definition, not generic nested instances. + +- **Signature:** `getSlot(propName: string): ResultSection[] | undefined` +```ts +// Figma property "Content" must be type SLOT in component properties +const content = instance.getSlot('Content') + +export default { + example: figma.code`${content}`, + // ... +} +``` + +### Interpolation in tagged templates + +When interpolating values in tagged templates, use the correct wrapping: +- **String values** (`getString`, `getEnum`, `textContent`): wrap in quotes → `variant="${variant}"` +- **Instance/section values** (`executeTemplate().example`): wrap in braces → `icon={${iconCode}}` +- **Slot sections** (`getSlot()` result — `ResultSection[] | undefined`): interpolate directly inside `` figma.code`...` `` (same shape as nested snippet sections), e.g. `` figma.code`` `` — do not treat as a plain string +- **Boolean bare props**: use conditional → `${disabled ? 'disabled' : ''}` + +### Finding descendant layers + +When you need to access children that aren't exposed as component properties: + +| Method | Use when | +|---|---| +| `instance.getInstanceSwap('PropName')` | Figma property type is **INSTANCE_SWAP** (fixed swapped instance) | +| `instance.getSlot('PropName')` | Figma property type is **SLOT** (freeform content region) | +| `instance.findInstance('LayerName')` | You know the child layer name (no component property) | +| `instance.findText('LayerName')` → `.textContent` | You need text content from a named text layer | +| `instance.findConnectedInstance('id')` | You know the child's Code Connect `id` | +| `instance.findConnectedInstances(fn)` | You need multiple connected children matching a filter | +| `instance.findLayers(fn)` | You need any layers (text + instances) matching a filter | + +### Nested configurable instances + +A component may contain child instances that are **not exposed as component properties** (no INSTANCE_SWAP) but are still **independently configurable** — they have their own variants, properties, or swap slots. These must be resolved dynamically, not hardcoded. + +1. **Check whether the child already has a Code Connect template** — use `get_code_connect_suggestions` or check existing `.figma.ts` files in the project. +2. **If no template exists, create one** for the child so it renders correctly both standalone and when nested. +3. **Reference the child from the parent** using `findInstance()` or `findConnectedInstance()`, then call `executeTemplate()`. + +```ts +// Parent template — the Badge child isn't a prop, but it's configurable +const badge = instance.findInstance('Status Badge') +let badgeCode +if (badge && badge.type === 'INSTANCE') { + badgeCode = badge.executeTemplate().example +} + +export default { + example: figma.code`${badgeCode}`, + // ... +} +``` + +This applies to icons, badges, labels, and any other nested instance that is configurable by itself — always connect them and render dynamically, never hardcode their content. + +### Nested component example + +For multi-level nested components or metadata prop passing between templates, see [Code Connect Examples](#reference--code-connect-examples). + +```ts +const icon = instance.getInstanceSwap('Icon') +let iconSnippet +if (icon && icon.type === 'INSTANCE') { + iconSnippet = icon.executeTemplate().example +} + +export default { + example: figma.code``, + // ... +} +``` + +### Conditional props + +```ts +const variant = instance.getEnum('Variant', { 'Primary': 'primary', 'Secondary': 'secondary' }) +const disabled = instance.getBoolean('Disabled') + +export default { + example: figma.code` + + `, + // ... +} +``` + +## Step 6: Validate + +Read back the `.figma.ts` file and review it against the following: + +- **Property coverage** — every Figma property from Step 3 should be accounted for in the template. Flag any that are missing and ask the user if they were intentionally omitted. +- **Valid, correctly typed code** — all emitted code must be valid and correctly typed against the code component's `Props` interface. Never make up component properties — if a Figma property has no corresponding code prop, omit it rather than invent one. +- **No hardcoded children** — verify that every INSTANCE_SWAP property and child component slot uses the dynamic APIs (`getInstanceSwap()`, `findInstance()`, `findConnectedInstance()`, etc.) with `executeTemplate()`. No slot should contain hardcoded component content. +- **Rules and Pitfalls** — check for the common mistakes listed below (string concatenation of template results, unnecessary `hasCodeConnect()` guards, missing `type === 'INSTANCE'` checks, etc.) +- **Interpolation wrapping** — strings (`getString`, `getEnum`, `textContent`) wrapped in quotes, instance/section values (`executeTemplate().example`) wrapped in braces, slot sections (`getSlot`) interpolated as snippet sections inside `` figma.code`...` ``, booleans using conditionals + +If anything looks uncertain, consult [Code Connect Template API Reference](#reference--code-connect-template-api-reference) for API details and [Code Connect Examples](#reference--code-connect-examples) for complex nesting. + +## Inline Quick Reference + +### `instance.*` Methods + +| Method | Signature | Returns | +|---|---|---| +| `getString` | `(propName: string)` | `string` | +| `getBoolean` | `(propName: string, mapping?: { true: any, false: any })` | `boolean \| any` | +| `getEnum` | `(propName: string, mapping: { [figmaVal]: codeVal })` | `any` | +| `getInstanceSwap` | `(propName: string)` | `InstanceHandle \| null` | +| `getSlot` | `(propName: string)` | `ResultSection[] \| undefined` | +| `getPropertyValue` | `(propName: string)` | `string \| boolean` | +| `findInstance` | `(layerName: string, opts?: SelectorOptions)` | `InstanceHandle \| ErrorHandle` | +| `findText` | `(layerName: string, opts?: SelectorOptions)` | `TextHandle \| ErrorHandle` | +| `findConnectedInstance` | `(codeConnectId: string, opts?: SelectorOptions)` | `InstanceHandle \| ErrorHandle` | +| `findConnectedInstances` | `(selector: (node) => boolean, opts?: SelectorOptions)` | `InstanceHandle[]` | +| `findLayers` | `(selector: (node) => boolean, opts?: SelectorOptions)` | `(InstanceHandle \| TextHandle)[]` | + +### InstanceHandle Methods + +| Method | Returns | +|---|---| +| `hasCodeConnect()` | `boolean` | +| `executeTemplate()` | `{ example: ResultSection[], metadata: Metadata }` | +| `codeConnectId()` | `string \| null` | + +### TextHandle Properties + +| Property | Type | +|---|---| +| `.textContent` | `string` | +| `.name` | `string` | + +### SelectorOptions + +```ts +{ path?: string[], traverseInstances?: boolean } +``` + +- `traverseInstances: true` — required when the target lives inside another nested instance. Without it, `findInstance`/`findText` only search the current instance's own layers and stop at nested instance boundaries. +- `path: string[]` — disambiguates when multiple descendants share the same layer name. Lists parent layer names that must appear on the path to the target. + +**Examples:** + +```ts +// Layer hierarchy: +// A > C (instance) > "mychild" +// "mychild" sits inside nested instance C, so plain findInstance returns ErrorHandle. +instance.findInstance('mychild', { traverseInstances: true }) + +// Layer hierarchy: +// A > C (instance) > "mychild" +// A > D (instance) > "mychild" +// Two "mychild" layers exist — use path to pick the one under C. +instance.findInstance('mychild', { traverseInstances: true, path: ['C'] }) +``` + +**When to reach into a nested instance from a parent template:** only when the parent code component (from Step 4) takes the nested layer as a prop value itself (e.g. `} />` — A forwards B into C). If the parent just composes C and C renders B internally, resolve C with `executeTemplate()` and let C's own template handle B — don't duplicate B's rendering at the parent level. + +### Export Structure -- If the tool returns **"No published components found in this selection"** → inform the user and stop. The components may need to be published to a team library first. -- If the tool returns **"All component instances in this selection are already connected to code via Code Connect"** → inform the user that everything is already mapped. -- Otherwise, the response contains a list of unmapped components, each with: - - Component name - - Node ID - - Component properties (JSON with prop names and values) - - A thumbnail image of the component (for visual inspection) +```ts +export default { + example: figma.code`...`, // Required: ResultSection[] + id: 'component-name', // Required: string + imports: ['import { X } from "..."'], // Optional: string[] + metadata: { nestable: true, props: {} } // Optional +} +``` + +## Rules and Pitfalls + +1. **Never string-concatenate template results.** `executeTemplate().example` is a `ResultSection[]` object, not a string. Using `+` or `.join()` produces `[object Object]`. Always interpolate inside tagged templates: `` figma.code`${snippet1}${snippet2}` `` + +2. **Do not use `hasCodeConnect()` guards.** Call `executeTemplate()` directly on any instance after a `type === 'INSTANCE'` check. The runtime handles instances without Code Connect automatically. + + ```ts + // WRONG — hasCodeConnect() gate drops non-CC instances + if (icon && icon.type === 'INSTANCE' && icon.hasCodeConnect()) { + iconCode = icon.executeTemplate().example + } + + // CORRECT — let the runtime handle all instances + if (icon && icon.type === 'INSTANCE') { + iconCode = icon.executeTemplate().example + } + ``` + +3. **Check `type === 'INSTANCE'` before calling `executeTemplate()`.** `findInstance()`, `findConnectedInstance()`, and `findText()` return an `ErrorHandle` (truthy, but not a real node) on failure — not `null`. Always add a type check to avoid crashes: `if (child && child.type === 'INSTANCE') { ... }` + +4. **Prefer `getInstanceSwap()` over `findInstance()`** when a component property exists for the slot. `findInstance('Star Icon')` breaks when the icon is swapped to a different name; `getInstanceSwap('Icon')` always works regardless of which instance is in the slot. + +5. **Use `getSlot()` only when the Figma property type is `SLOT`.** For **INSTANCE_SWAP** props, use `getInstanceSwap()` (returns an `InstanceHandle`). `getSlot()` returns structured slot sections, not instances — never call `executeTemplate()` on its return value. + +6. **Property names are case-sensitive** and must exactly match what `get_context_for_code_connect` returns. + +7. **Handle multiple template arrays correctly.** When iterating over children, set each result in a separate variable and interpolate them individually — do not use `.map().join()`: + ```ts + // Wrong: + items.map(n => n.executeTemplate().example).join('\n') + + // Correct — use separate variables: + const child1 = items[0]?.executeTemplate().example + const child2 = items[1]?.executeTemplate().example + export default { example: figma.code`${child1}${child2}` } + ``` + +7. **Never hardcode slot or children content.** Always resolve child instances dynamically — use `getInstanceSwap()` for INSTANCE_SWAP properties, `findInstance()`/`findConnectedInstance()` for direct children — and render them via `executeTemplate()`. Never construct JSX from a layer name (e.g., ``) or guess import paths. If an instance has no Code Connect, omit it — do not add a hardcoded fallback. + + ```ts + // WRONG — hardcodes the icon from its layer name + example: figma.code`` + + // CORRECT — resolves dynamically, works for any swapped icon + const icon = instance.findInstance('Icon') + let iconCode + if (icon && icon.type === 'INSTANCE') { + iconCode = icon.executeTemplate().example + } + example: figma.code`...` + ``` + +8. **Attempt to represent every Figma property via a code prop.** The code component's `Props` interface (from Step 4) is the authoritative list of attribute names. For each Figma property, figure out the right way to represent it using the API methods from Step 5 — direct name match, value transformation, or whatever fits. If no code prop fits at all, omit it — don't invent a prop name. + +## Complete Worked Example + +Given URL: `https://figma.com/design/abc123/MyFile?node-id=42-100` + +**Step 1:** Parse the URL. +- `fileKey` = `abc123` +- `nodeId` = `42-100` → `42:100` + +**Step 2:** Call `get_code_connect_suggestions` with `fileKey: "abc123"`, `nodeId: "42:100"`, `excludeMappingPrompt: true`. +Response returns one component with `mainComponentNodeId: "42:100"`. If the response were empty, stop and inform the user. If multiple components were returned, repeat Steps 3–6 for each. + +**Step 3:** Call `get_context_for_code_connect` with `fileKey: "abc123"`, `nodeId: "42:100"` (from Step 2), `clientFrameworks: ["react"]`, `clientLanguages: ["typescript"]`. + +Response includes properties: +- Label (TEXT) +- Variant (VARIANT): Primary, Secondary +- Size (VARIANT): Small, Medium, Large +- Disabled (BOOLEAN) +- Has Icon (BOOLEAN) +- Icon (INSTANCE_SWAP) + +**Step 4:** Search codebase → find `Button` component. Read its source to confirm props: `variant`, `size`, `disabled`, `icon`, `children`. Import path: `"primitives"`. + +**Step 5:** Create `src/figma/primitives/Button.figma.ts`: + +```ts +// url=https://figma.com/design/abc123/MyFile?node-id=42-100 +// source=src/components/Button.tsx +// component=Button +import figma from 'figma' +const instance = figma.selectedInstance + +const label = instance.getString('Label') +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 hasIcon = instance.getBoolean('Has Icon') +const icon = hasIcon ? instance.getInstanceSwap('Icon') : null +let iconCode +if (icon && icon.type === 'INSTANCE') { + iconCode = icon.executeTemplate().example +} + +export default { + example: figma.code` + + `, + imports: ['import { Button } from "primitives"'], + id: 'button', + metadata: { nestable: true } +} +``` -### Step 2: Scan Codebase for Matching Components +**Step 6:** Read back file to verify syntax. -For each unmapped component returned by `get_code_connect_suggestions`, search the codebase for a matching code component. +## Additional Reference -**What to look for:** +For advanced patterns (multi-level nested components, `findConnectedInstances` filtering, metadata prop passing between parent/child templates): -- Component names that match or are similar to the Figma component name -- Component structure that aligns with the Figma hierarchy -- Props that correspond to Figma properties (variants, text, styles) -- Files in typical component directories (`src/components/`, `components/`, `ui/`, etc.) +- [Code Connect Template API Reference](#reference--code-connect-template-api-reference) — Full Code Connect API reference +- [Code Connect Examples](#reference--code-connect-examples) — Advanced nesting, metadata props, and descendant patterns -**Search strategy:** +--- -1. Search for component files with matching names -2. Read candidate files to check structure and props -3. Compare the code component's props with the Figma component properties returned in Step 1 -4. Detect the programming language (TypeScript, JavaScript) and framework (React, Vue, etc.) -5. Identify the best match based on structural similarity, weighing: - - Prop names and their correspondence to Figma properties - - Default values that match Figma defaults - - CSS classes or style objects - - Descriptive comments that clarify intent -6. If multiple candidates are equally good, pick the one with the closest prop-interface match and document your reasoning in a 1-2 sentence comment before your tool call +## Reference — Code Connect Examples -**Example search patterns:** +### Contents +- [Basic component property retrieval](#basic-component-property-retrieval) +- [Descendants and recursive templating](#descendants-and-recursive-templating) + - [instance.metadata](#instancemetadata) + - [instance.example](#instanceexample) + - [Descendant methods](#descendant-methods) -- If Figma component is "PrimaryButton", search for `Button.tsx`, `PrimaryButton.tsx`, `Button.jsx` -- Check common component paths: `src/components/`, `app/components/`, `lib/ui/` -- Look for variant props like `variant`, `size`, `color` that match Figma variants +### Basic component property retrieval + +- `instance.getEnum`: if you want to map a variant value to something specific +- `instance.getString`: if you want a text property value, or a boolean/variant value back as a string. +- `instance.getBoolean`: if you want to map a boolean value to something specific +- `instance.getInstanceSwap`: if you want to access a swappable instance descendant by property name + +#### Examples + +Both of these are valid, but depending on required outcome, one or the other would be preferred. + +```js +const variantMapping = instance.getEnum("Variant", { + Primary: "primary", + Secondary: "secondary", +}); +const variantTransform = instance.getString("Variant").toLowerCase(); +``` -### Step 3: Present Matches to User +Booleans can also be handled similarly. These aren't the best example, but either approach may be preferred depending on the logic of the snippet. -Present your findings and let the user choose which mappings to create. The user can accept all, some, or none of the suggested mappings. +```js +const booleanMapping = instance.getBoolean("Is Highlighted", { + true: "is-highlighted", + false: undefined, +}); +const boolean = instance.getString("Is Highlighted") === "true"; +``` -**Present matches in this format:** +Text properties are always getString() +```js +const label = instance.getString("Label"); ``` -The following components match the design: -- [ComponentName](path/to/component): DesignComponentName at nodeId [nodeId](figmaUrl?node-id=X-Y) -- [AnotherComponent](path/to/another): AnotherDesign at nodeId [nodeId2](figmaUrl?node-id=X-Y) -Would you like to connect these components? You can accept all, select specific ones, or skip. +### Descendants and recursive templating + +There are many ways to find descendant layers. Deciding which to use depends on what descendant information is relevant in the parent context. Descendant context could be many things: layer properties, layer name, text content, total descendant count, or a full Code Connect snippet example. + +Descendant instances that have Code Connect on them can have `example` (the code snippet object), or `metadata` custom information. + +If `node.hasCodeConnect()`, these can be accessed with `const { example, metadata } = node.executeTemplate()`. + +#### `instance.metadata` + +**`metadata.props` is how you can surface non-snippet information upwards** + +Any string value can be stored in props. This is additional information to the example snippet. Handy for scenarios where you want single values to be referenced in parent contexts instead of an entire snippet. + +> **Important:** For a child template to be discoverable by parent templates (via `findConnectedInstance`, `findConnectedInstances`, or `hasCodeConnect()`), `nestable: true` must be set in **both** the template's `metadata` export **and** in `templateDataJson` when registering via `add_code_connect_map` — e.g. `'{"isParserless": true, "nestable": true}'`. If `nestable` is missing from `templateDataJson`, the child template will not be loaded into the parent's evaluation context. + +```js +export default { + example: figma.html`normal stuff`, + id: "child", + metadata: { nestable: true, props: { special: "Special Stuff!!! 🤩" } }, +}; ``` -**If no exact match is found for a component:** +```js +const child = instance.findConnectedInstance("child"); + +if (child && child.type === 'INSTANCE') { + export default { + example: figma.html`${child.executeTemplate().metadata?.props?.special}`, + id: "parent", + }; +} +``` -- Show the 2 closest candidates -- Explain the differences -- Ask the user to confirm which component to use or provide the correct path +The output of these templates would be: + +```html + +normal stuff + + +Special Stuff!!! 🤩 +``` + +#### `instance.example` + +`instance.executeTemplate().example` contains the code snippet (or an error if the snippet is invalid). It is an array, but should always be treated like a single value and can render just fine in figma's tagged template literals. + +**`example` is an object, and should be interpolated via tagged template literals** + +If the example is being used as is, stringifying it in a tagged template literal is required, otherwise it'll yield `[object Object]`. + +```js +const thing = `${node.executeTemplate().example}`; // Will not work downstream +const thing = figma.html`${node.executeTemplate().example}`; // WILL work downstream + +return { + example: figma.html`${thing}`, +}; +``` + +Arrays should be avoided when referring to template examples, joining them will render to `[object Object]`. + +```js +const thing = []; +thing.push(figma.html`${node.executeTemplate().example}`); + +return { + example: figma.html`${thing.join("\n")}`, // BAD: Will not work + example: figma.html`${thing[0]}`, // Will work...but defeats the purpose of an array and we should use a variable instead. +}; +``` + +Therefore, If you have multiple children examples, set each in a variable. + +```js +return { + example: figma.html`${thingStart}${thing}${thingEnd}`, +}; +``` + +**`example[0].code` is a string when the example is valid** + +Digging into the example to get to the snippet string can be useful in rare cases, but requires validation first in case the template can't render. This is rarely recommended and only good if the default template is undesired and `metadata.props` is not an appropriate approach. + +```js +const example = node.executeTemplate()?.example[0]; +if (example?.type === "CODE") { + // do something with snippet string + thing = example.code.replace("abc", "123"); +} else { + // handle error + thing = `ERROR: ${example?.message}`; +} +``` -**If the user declines all mappings**, inform them and stop. No further tool calls are needed. +#### Descendant methods -### Step 4: Create Code Connect Mappings +**`instance` nodes** + +`instance.getInstanceSwap` and `instance.getString` are the preferred ways to access content when component properties are tied to the values you are looking for. However, if you need to access text node content or instances that are not bound to component properties, there are other methods to get you there: + +- `instance.hasCodeConnect()`: Whether or not the instance has code connect on it. +- `instance.codeConnectId()`: String to identify the connected component, set in code connect docs, usefule in filtering or finding the component via methods below. +- `instance.findInstance()`: Only returns a single instance, found by layer name. +- `instance.findText()`: Only returns a single text node, found by layer name. +- `instance.findConnectedInstance()`: Can use the `id` of a descendant (defined in the descendant's export) to remove any variability (layer naming, etc) and find a single instance of a specific component. Returns `ErrorHandle` on failure — check `result.type === 'INSTANCE'` before use. +- `instance.findConnectedInstances()`: To filter or find a list of connected instance descendants. `node.type` and `instance.hasCodeConnect()` are already enforced in this. `node.name` and `instance.codeConnectId()` can be used to filter in the handler. +- `instance.findLayers()`: To filter or find a list of any text or instance descendants. Instances do not have to be connected. `instance.hasCodeConnect()`, `node.type`, `node.name`, and `instance.codeConnectId()` can be used to filter in the handler. + +**`text` nodes** + +Text nodes only have a single value available in the API: + +- `text.textContent`: returns the text content for the node. + +##### findInstance versus getInstanceSwap + +```js +const hasIcon = instance.getBoolean("Has Icon"); +let icon = null; +if (hasIcon) { + const iconInstance = instance.findInstance("Star Icon"); // INCORRECT: Will be null when icons with other names are in this slot. + const iconInstance = instance.getInstanceSwap("Icon"); // CORRECT: Will refer to any instance in this slot. + if (iconInstance && iconInstance.type === 'INSTANCE' && iconInstance.hasCodeConnect()) { + icon = iconInstance.executeTemplate().example; + } +} +``` + +##### findLayers to get a list of strings + +```js +const items = []; +instance.findLayers((node) => { + if (node.type === "TEXT") { + items.push(`
  • ${node.textContent}
  • `); + } +}); +``` + +##### findLayers to iterate with an index + +```js +const items = []; +let i = 0; +instance.findConnectedInstances((node) => { + if (node.codeConnectId() === "button") { + items.push( + figma.code`${ + node.executeTemplate().metadata.props.label + }`, + ); + i++; + } +}); +``` + +##### Sophisticated inheritance, three generation example + +```js +// url=https://www.figma.com/design?node-id=7699-6920 +// source=src/components/Grandparent.js +// component=Grandparent + +const figma = require("figma"); +const instance = figma.selectedInstance; + +const parents = instance.findConnectedInstances( + (node) => node.codeConnectId() === "parent", +); + +export default { + example: figma.html` +${parents + .map( + (node, i) => node.executeTemplate().metadata.props.special + " index: " + i, + ) + .join("\n")} +`, + id: "grandparent", + metadata: { nestable: true }, +}; +``` + +```js +// url=https://www.figma.com/design?node-id=7699-6921 +// source=src/components/Parent.js +// component=Parent + +const figma = require("figma"); +const instance = figma.selectedInstance; + +let childCode; +let special; +const node = instance.findConnectedInstance("child"); +if (node && node.type === 'INSTANCE') { + const { metadata, example } = node.executeTemplate(); + childCode = example; + special = `${metadata.props.special}`; +} + +export default { + example: figma.html` +${childCode} +`, + id: "parent", + metadata: { nestable: true, props: { special } }, +}; +``` + +```js +// url=https://www.figma.com/design?node-id=7699-6922 +// source=src/components/Child.js +// component=Child + +const figma = require("figma"); + +export default { + example: figma.html`normal stuff`, + id: "child", + metadata: { nestable: true, props: { special: "Special Stuff!!! 🤩" } }, +}; +``` + +```html + +normal stuff + + + + normal stuff + + + + + Special Stuff!!! 🤩 index: 0 + Special Stuff!!! 🤩 index: 1 + Special Stuff!!! 🤩 index: 2 + +``` + +--- + +## Reference — Code Connect Template API Reference + +### Overview + +Code Connect uses template files (`.figma.js`) to connect your code components to Figma designs. This API reference covers the complete template system for creating these mappings. + +### Quick Start + +A minimal Code Connect template: + +```javascript +// url=https://www.figma.com/file/abc123/MyFile?node-id=123-456 +// source=src/components/Button.tsx +// component=Button +const figma = require('figma') +const instance = figma.selectedInstance + +const label = instance.getString('Label') + +export default { + example: figma.code` + `, + imports: ['import { Button } from "./Button"'], + id: 'button', + metadata: { + nestable: true + } +} +``` + +--- + +### Core API Reference + +#### `figma` Object + +Import with: `const figma = require('figma')` + +##### `figma.selectedInstance: InstanceHandle` + +The currently selected Figma component instance. This is your main entry point for accessing component data. + +##### Tagged Template Literals + +Use these to wrap your code snippets for proper syntax highlighting: + +| Template | Use For | +|----------|---------| +| `figma.code` | Generic code (fallback) | +| `figma.tsx` | React/TypeScript JSX | +| `figma.jsx` | React JavaScript | +| `figma.html` | HTML markup | +| `figma.swift` | Swift code | +| `figma.kotlin` | Kotlin code | **Example:** +```javascript +const example = figma.tsx`` +``` + +**Important:** Never use string concatenation on template results. Always wrap in `figma.code`: +```javascript +// Wrong +const snippet = iconSnippet + buttonSnippet + +// Correct +const snippet = figma.code`${iconSnippet}${buttonSnippet}` +``` + +##### `figma.helpers` + +Helper utilities for rendering code patterns: + +**React Helpers:** +```javascript +figma.helpers.react.renderProp('propName', value) +figma.helpers.react.renderChildren(children) +figma.helpers.react.jsxElement('') ``` -send_code_connect_mappings( - fileKey=":fileKey", - nodeId="1:2", - mappings=[ - { nodeId: "1:2", componentName: "Button", source: "src/components/Button.tsx", label: "React" }, - { nodeId: "1:5", componentName: "Card", source: "src/components/Card.tsx", label: "React" } - ] -) + +##### `figma.properties` + +Access child components by type: + +```javascript +const buttons = figma.properties.children(['Button']) +const icons = figma.properties.children(['Icon', 'Avatar']) ``` -**Key parameters for each mapping:** +--- -- `nodeId`: The Figma node ID (with colon format: `1:2`) -- `componentName`: Name of the component to connect (e.g., "Button", "Card") -- `source`: Path to the code component file (relative to project root) -- `label`: The framework or language label for this Code Connect mapping. Valid values include: - - Web: 'React', 'Web Components', 'Vue', 'Svelte', 'Storybook', 'Javascript' - - iOS: 'Swift UIKit', 'Objective-C UIKit', 'SwiftUI' - - Android: 'Compose', 'Java', 'Kotlin', 'Android XML Layout' - - Cross-platform: 'Flutter' - - Docs: 'Markdown' +### Working with Properties -**After the call:** +#### Reading Component Properties -- On success: the tool confirms the mappings were created -- On error: the tool reports which specific mappings failed and why (e.g., "Component is already mapped to code", "Published component not found", "Insufficient permissions") +##### `getString(propName: string): string` -**Provide a summary** after processing: +Gets a text property value from the Figma component. +```javascript +const label = instance.getString('Label') +const placeholder = instance.getString('Placeholder Text') ``` -Code Connect Summary: -- Successfully connected: 3 - - Button (1:2) → src/components/Button.tsx - - Card (1:5) → src/components/Card.tsx - - Input (1:8) → src/components/Input.tsx -- Could not connect: 1 - - CustomWidget (1:10) - No matching component found in codebase + +##### `getBoolean(propName: string, mapping?: object): boolean | any` + +Gets a boolean property with optional value mapping. + +```javascript +// Simple boolean +const isDisabled = instance.getBoolean('Disabled') + +// Map to custom values +const hasIcon = instance.getBoolean('Has Icon', { + true: figma.code``, + false: null +}) +``` + +##### `getEnum(propName: string, mapping: object): any` + +Maps Figma variant values to code values. + +```javascript +const size = instance.getEnum('Size', { + Small: 'sm', + Medium: 'md', + Large: 'lg' +}) + +const variant = instance.getEnum('Variant', { + Primary: 'primary', + Secondary: 'secondary', + Tertiary: 'tertiary' +}) +``` + +##### `getInstanceSwap(propName: string): InstanceHandle` + +Gets a swapped instance from an instance swap property. + +```javascript +const icon = instance.getInstanceSwap('Icon') +if (icon) { + const iconCode = icon.executeTemplate().example +} ``` -## Examples +##### `getSlot(propName: string): ResultSection[] | undefined` + +Reads a Figma component property whose type is **`SLOT`** (not **INSTANCE_SWAP**). Returns a `ResultSection[]` containing a slot section (`type: 'SLOT'`). Returns `undefined` if the property is missing or invalid. Do not call `executeTemplate()` on this value — unlike `getInstanceSwap()`, it is not an `InstanceHandle`. + +```javascript +const content = instance.getSlot('Content') + +export default { + example: figma.code`${content}` +} +``` + +##### `getPropertyValue(propName: string): string | boolean` + +Gets the raw property value without mapping. + +```javascript +const rawValue = instance.getPropertyValue('Some Property') +``` + +#### Property Patterns + +##### Conditional Properties -### Example 1: Connecting a Button Component +```javascript +const showIcon = instance.getBoolean('Has Icon') +const icon = showIcon ? instance.findInstance('Icon') : null -User says: "Connect this Figma button to my code: https://figma.com/design/kL9xQn2VwM8pYrTb4ZcHjF/DesignSystem?node-id=42-15" +export default { + example: figma.code` + + ` +} +``` -**Actions:** +##### Combining Properties + +```javascript +const variant = instance.getEnum('Variant', { Primary: 'primary', Secondary: 'secondary' }) +const size = instance.getEnum('Size', { Small: 'sm', Large: 'lg' }) +const disabled = instance.getBoolean('Disabled') + +export default { + example: figma.code` + + `, + imports: ['import { Button } from "@/components/Button"'], + id: 'button', + metadata: { + nestable: true + } +} +``` + +#### Card with Children + +```javascript +// url=https://www.figma.com/file/abc/Components?node-id=10-20 +// source=src/components/Card.tsx +// component=Card + +const figma = require('figma') +const instance = figma.selectedInstance + +const heading = instance.findText('Heading') +const body = instance.findText('Body') +const actions = figma.properties.children(['Button']) +const variant = instance.getEnum('Variant', { + Elevated: 'elevated', + Outlined: 'outlined', + Filled: 'filled' +}) + +export default { + example: figma.tsx` + + + ${heading.textContent} + + + ${body.textContent} + + + ${actions.map(action => action.executeTemplate().example).join('\n')} + + + `, + imports: ['import { Card } from "@/components/Card"'], + id: 'card', + metadata: { + nestable: false + } +} +``` + +#### Form Field with Validation + +```javascript +// url=https://www.figma.com/file/abc/Components?node-id=30-40 +// source=src/components/TextField.tsx +// component=TextField + +const figma = require('figma') +const instance = figma.selectedInstance + +const label = instance.getString('Label') +const placeholder = instance.getString('Placeholder') +const helperText = instance.findText('Helper Text') +const errorState = instance.getEnum('State', { + Default: false, + Error: true +}) +const required = instance.getBoolean('Required') +const disabled = instance.getBoolean('Disabled') + +export default { + example: figma.tsx` + + `, + imports: ['import { TextField } from "@/components/TextField"'], + id: 'text-field' +} +``` + +#### Navigation with Dynamic Items + +```javascript +// url=https://www.figma.com/file/abc/Components?node-id=50-60 +// source=src/components/Navigation.tsx +// component=Navigation + +const figma = require('figma') +const instance = figma.selectedInstance + +const items = instance.findConnectedInstances(node => { + return node.codeConnectId() === 'nav-item' +}) + +const direction = instance.getEnum('Direction', { + Horizontal: 'horizontal', + Vertical: 'vertical' +}) + +export default { + example: figma.tsx` + + ${items.map(item => item.executeTemplate().example).join('\n')} + + `, + imports: ['import { Navigation } from "@/components/Navigation"'], + id: 'navigation', + metadata: { + nestable: false + } +} +``` + +--- + +### Best Practices + +#### 1. Use Descriptive IDs + +```javascript +// Good - clear and descriptive +export default { + id: 'primary-button', + // ... +} + +// Avoid - too generic +export default { + id: 'btn', + // ... +} +``` + +#### 2. Handle Missing Properties Gracefully + +```javascript +// Good - check type before calling hasCodeConnect +const icon = instance.findInstance('Icon') +const iconCode = icon && icon.type === 'INSTANCE' && icon.hasCodeConnect() + ? icon.executeTemplate().example + : null + +// Avoid - assumes icon exists +const iconCode = instance.findInstance('Icon').executeTemplate().example +``` + +#### 3. Use Appropriate Tagged Templates + +```javascript +// Good - use specific template for language +const example = figma.tsx`