What a frame actually contains
A Figma frame is a tree of shapes with positions, fills, strokes, text runs and layout constraints. That is a complete description of how something looks at one size. It is not a description of what anything is.
| In the file | Must be inferred | |
|---|---|---|
| Structure | A group of rectangles and text at these coordinates | That this group is a Card, and that it is the same Card used on nine other screens |
| Colour | Fill is #6b7280 | Whether that is muted text, a border, a disabled state or a placeholder |
| Spacing | 32px between these two elements | Whether 32 is a scale step, a one-off, or the result of someone nudging |
| Responsiveness | Constraints, and whatever breakpoint frames exist | What happens at every width between them |
| Semantics | Text with a larger size and heavier weight | Whether it is an h1, an h2, or styled text that is not a heading at all |
Every row in the right column is a decision the converter has to make with no information. It will make each one plausibly and independently, which is why the output is simultaneously convincing at a glance and impossible to maintain.
A frame encodes appearance. Code needs identity and intent. The converter is not failing — the information was never in the file.
What generated code costs you
Accept the output as-is and four specific problems follow, all of which surface after the code is merged rather than while it is being reviewed.
- 1
No component reuse
The same card converted on five screens becomes five independent implementations. Nothing links them, so a change to the card is five changes, and someone will find only four.
- 2
Literal values everywhere
Converters emit
#6b7280because that is what the fill says. Your token layer is bypassed entirely, which means the design system you built is now decorative on those screens. - 3
Absolute or fragile layout
Position data converts to positioning. It matches the frame at exactly the frame's width and degrades at every other one, and the degradation is worst on the devices you tested least.
- 4
No semantics
Large heavy text becomes a styled
div. Screen readers get a page with no heading structure, keyboard users get no landmarks, and nobody notices until an audit.
The second one is the most consequential and the least visible in review. Once generated screens carry literal colour values, your codebase has two colour systems: the tokens, and whatever the design file said that day. A CI check that fails on hex outside the token file catches it at the door.
Mapping beats generation
The productive reframe is to stop asking the tool to write code and start telling it which code already exists. Figma's Code Connect does exactly this: it links a design component to your real code component, so Dev Mode shows the actual component and its props rather than generated CSS.
That changes the problem from generation to lookup, and lookup is a problem that can be correct.
| Generate | Map | |
|---|---|---|
| Produces | New markup approximating the frame | A reference to the component you already maintain |
| Reuse | None — every conversion is fresh | Total, by construction |
| Tokens | Bypassed; literals emitted | Preserved; the component already uses them |
| Accessibility | Whatever the converter inferred | Whatever your component already does |
| Setup cost | None | One mapping per component, maintained as components change |
| Fails when | Always, slowly | A design uses something that does not exist in code yet |
That last row is the honest cost, and it is a real one: mapping only works for components that exist. A genuinely new design still needs building. But that is the correct division of labour — a human or an agent builds the new component once, and every subsequent use is a reference rather than a regeneration.
The target of the mapping is worth being concrete about. A handoff is finished when the code side looks like this — named roles with real values — rather than like a list of hexes recovered from a frame:
The naming-parity move
Underneath component mapping is a cheaper change that closes a surprising amount of the gap, and it needs no tooling at all: use the same names in both places.
Salesforce's SLDS 2 is the clearest published example. Its Figma library uses the same semantic styling-hook names as the CSS — the team's own examples are radius-border-4 and font-scale-4 — so designs map one-to-one to live code. Their stated goal is a shared vocabulary bridging design and development.
The effect is that a whole category of handoff bug stops existing. When a designer says font-scale-4 and a developer types font-scale-4, there is no translation step, so there is nowhere for meaning to leak. Compare that with a Figma style called "Heading / Large" mapping to a CSS variable called --text-2xl: every handoff is a lookup, and every lookup can go wrong.
| Mismatched | Matched | |
|---|---|---|
| Handoff | A translation step per property | Copy the name |
| Review | "Is that the right grey?" requires opening both tools | The name is either right or it is not |
| An agent reading both | Two vocabularies, no stated relationship, silent guessing | One vocabulary |
If you do one thing from this article, rename your Figma variables to match your CSS custom properties exactly. It costs an afternoon, needs no plugin, and removes a permanent tax on every handoff. Flat, lowercase, hyphenated names survive both tools — more on naming for portability.
When the design system lives in Figma
Plenty of teams have a thorough Figma library and a codebase that only partly reflects it. The instinct is to find a tool that closes the gap automatically. There is a cheaper move that works better.
A Figma library contains the decisions — the scale, the roles, the component set, the spacing rhythm. Those decisions transfer perfectly well as text, and text is the format both a developer and a coding agent can act on. Extracting them into a token file plus a written brief is a day of work and it makes every subsequent conversion unnecessary, because the code side now has the same information the design side does.
We sampled 299 DESIGN.md files written to carry exactly that information to AI agents, and most of them do not: 86% specify colours as raw hex with no semantic role, 76% state no prohibitions, 69% define no dark mode, and 44% state no concrete size value anywhere. A brief extracted from a real Figma library, done properly, beats almost all of them — you already have the numbers.
- 1
Export the variables as tokens, with roles
Not the raw palette. The roles: which colour is muted text, which is a border, which is a disabled state. If your Figma variables are named by hue, this is the moment to rename them by role in both places at once.
- 2
Write down the scales as numbers
Type sizes, spacing steps, radii. The library already contains these; the code side usually has a subset plus improvisation.
- 3
Write down what the library refuses to do
The prohibitions are in the library implicitly — no shadows anywhere, no weight above 600 — and they are the highest-value thing to make explicit, because they are invisible to any automated extraction.
- 4
Map the components that already exist in code
Only now is tooling worth introducing, and only for components on both sides. Everything unmapped is a build, and knowing which is which is itself useful.
Identity Forge kits are that artefact in prebuilt form: 28 semantic colour roles across light and dark, type and spacing scales, motifs and explicit do's and don'ts, exportable as CSS variables, Tailwind @theme, a shadcn registry item or DTCG/W3C JSON. Browse the kits, or read how to write the brief.
What to expect from the current tools
Calibrated expectations, by task:
| Realistic outcome | |
|---|---|
| A throwaway prototype from a mockup | Good. Structural debt does not matter in code you will delete |
| Extracting measurements and values | Good, and underrated. Dev Mode inspection is the boring, reliable win |
| A new screen using existing components | Good with mapping configured. Poor without it |
| Production markup from a complex frame | Poor. Visually close, structurally wrong, and the cleanup usually exceeds writing it |
| Converting a whole design system | Not a conversion problem. Extract the decisions as text instead |
The second row deserves more credit than it gets. Reliable inspection — exact values, real token names, actual component props — removes a genuine daily friction and never claims to do more than it does.
Can AI convert Figma designs to production code?
It can produce code that looks like the frame. Whether that is production code depends on structure, and structure is what a frame does not contain — component identity, semantic roles, responsive behaviour between breakpoints. Expect visually close and structurally wrong, and budget for the cleanup.
What is Figma Code Connect?
A feature that links design components to your real code components, so Dev Mode shows the actual component and its props instead of generated CSS. It changes the problem from generating new markup to referencing code you already maintain, which preserves reuse, tokens and accessibility work.
Why does design-to-code output use hardcoded colours?
Because the fill in the frame is a value, and the converter has no way to know which semantic role that value plays. Matching your Figma variable names to your CSS token names is what gives the tooling something to reference instead of a hex code.
How do I get my Figma design system into code?
Not by converting screens. Export the variables as semantic tokens with roles attached, write the scales down as numbers, write down what the library refuses to do, and only then map the components that exist on both sides. That is a day of work and it makes ongoing conversion unnecessary.
Should designers and developers use the same token names?
Yes, and it is the highest-return change available for the effort. When a designer says font-scale-4 and a developer types font-scale-4, there is no translation step and therefore no place for meaning to leak. Salesforce built SLDS 2's Figma library on exactly this parity.