Figma Code Connect
June 29, 2026 · View on GitHub
Important: Icon mappings are configured separately through the Figma UI by the design team. There are intentionally no
.figma.tsxfiles for icons in this repo.
What is Code Connect?
Figma Code Connect links Figma components to their React implementations. When a designer inspects a component in Figma Dev Mode, they see a real code snippet — including the correct props — instead of a generic placeholder.
Especially powerful with AI agents and Figma MCP
When using an AI coding agent together with the Figma MCP server, Code Connect transforms how design-to-code workflows operate. Without it, the agent receives generic HTML with utility classes when reading a Figma design. With it, the agent gets back actual Forma 36 component names with the correct props already mapped — meaning it can implement a design directly in terms of the design system rather than reconstructing it from scratch.
In practice: give an agent a Figma link and ask it to implement the design, and it will output <Button variant="primary"> instead of <button class="bg-blue-500 px-4 py-2 rounded">. The accuracy and quality of the generated code improves significantly.
Where mappings live
Every component that has a Code Connect mapping has a *.figma.tsx file co-located next to its source:
packages/components/<component>/src/<Component>/<Component>.figma.tsx
Examples:
packages/components/button/src/Button/Button.figma.tsxpackages/components/card/src/Card/Card.figma.tsxpackages/components/badge/src/Badge/Badge.figma.tsx
The full list of mapped components is in figma.config.json under codeConnect.include.
Anatomy of a mapping file
import React from 'react';
import figma from '@figma/code-connect';
import { Button } from './Button';
const FIGMA_URL = 'https://www.figma.com/design/<file-id>?node-id=<node-id>';
figma.connect(Button, FIGMA_URL, {
props: {
variant: figma.enum('Type', {
Primary: 'primary',
Secondary: 'secondary',
}),
children: figma.string('Label'),
},
example: ({ variant, children }) => (
<Button variant={variant}>{children}</Button>
),
});
Key parts:
FIGMA_URL— points to the exact Figma node. Get it from the Figma URL when the component is selected (?node-id=...).props— maps Figma property names to React prop values usingfigma.enum,figma.string,figma.boolean,figma.instance,figma.nestedProps, etc.example— the JSX snippet shown to designers in Dev Mode.
Variant restrictions
When a Figma component has a State property (Default, Disabled, Hover, etc.), states that require a specific React prop need their own figma.connect call with a variant filter:
// State=Default — no extra props
figma.connect(Button, FIGMA_URL, {
variant: { State: 'Default' },
props: { ... },
example: ({ ... }) => <Button ...>{children}</Button>,
});
// State=Disabled — must pass isDisabled
figma.connect(Button, FIGMA_URL, {
variant: { State: 'Disabled' },
props: { ... },
example: ({ ... }) => <Button ... isDisabled>{children}</Button>,
});
Purely visual states (Hover, Focus) don't need a separate mapping since no React prop changes.
Adding or updating a mapping
- Locate or create
<Component>.figma.tsxnext to the component source. - Get the Figma node URL by selecting the component in Figma and copying the link (
Share → Copy link). - Map Figma properties to React props using the
figma.*helpers. - Run a dry-run to validate before publishing (see below).
Scripts
All scripts run from the repo root and require a FIGMA_ACCESS_TOKEN environment variable.
| Script | Description |
|---|---|
npm run figma:publish | Publish all mappings to Figma |
npm run figma:publish:dry | Dry run — validates and previews without publishing |
npm run figma:unpublish | Unpublish all mappings (see warning below) |
Always run figma:publish:dry first to catch errors before they reach Figma.
Warning:
figma:unpublishremoves all Code Connect mappings defined in this repo from Figma at once. Use it only when intentionally resetting everything. It cannot be scoped to a single component.
figma.config.json
figma.config.json at the repo root controls which files are picked up:
{
"codeConnect": {
"parser": "react",
"include": ["packages/components/**/*.figma.tsx", ...],
"exclude": ["**/*.test.*", "**/*.stories.*", ...],
"importPaths": {
"packages/components/navbar/src/*": "@contentful/f36-navbar",
"src/*": "@contentful/f36-components"
}
}
}
importPaths rewrites internal source paths to their published package names in the generated snippets.
Tips
- Dry run before publishing.
npm run figma:publish:dryprints exactly what would be sent to Figma, including any parse errors. - One file per component. If a component needs multiple
figma.connectcalls (e.g. variant restrictions), keep them all in the same.figma.tsxfile.