Most handoffs fail in a quiet way. The designer finishes the file. The developer opens it, sighs, and rebuilds half of it from scratch because the structure does not match how the code works.
Nobody did anything wrong. The designer and the developer were each organized, just in different ways. The fix is not a longer spec document. It is a shared structure that both sides can read.
This is how we set up a Figma to code handoff so that engineers can build from it directly.
Why handoffs break
We see the same five causes again and again:
- Names do not match. The button is "CTA big blue" in Figma and
PrimaryButtonin code. Everyone has to translate. - Screens, not components. The file has 80 finished screens but no list of the parts they are made of.
- Values are typed in by hand. A color is
#3B5BDBon one screen and#3B5CDCon another. Nobody knows which is right. - Only the happy path is drawn. There is no loading state, no empty state, no error. The developer invents them, and the designer sees the result at the end.
- No one checks the build. The finished page goes live without the designer looking at it in a browser.
Each of these is a structure problem. Fix the structure and most of the arguments go away.
Name things the same in both places
Agree on names before the first screen is drawn. This takes an hour and saves weeks.
A few simple rules:
- Use the component names the code will use. If the codebase has
Button,ModalandDataTable, so does Figma. - Use the same words for variants. If the code has
size="sm"andvariant="ghost", the Figma properties are called size and variant, with the same values. - Name layers by what they are, not how they look. "Sidebar" is useful. "Rectangle 214" is not.
- Keep one list of names that both sides can edit. A shared page in Figma or a markdown file in the repo is enough.
If the code does not exist yet, the designer proposes the names and the developer adjusts them in the first week. After that, nobody renames anything without telling the other side.
Components and variants
Build components first and screens second. A screen is mostly a set of components in a layout.
For each component, a developer should be able to see:
- The parts it is made of (icon, label, helper text)
- The variants that exist (primary, secondary, danger)
- The sizes that exist
- What changes on hover, focus, pressed and disabled
- How it behaves when the content is too long
Use Figma component properties and variants for this, not a pile of separate frames. A button with variant, size and state properties maps almost one to one onto a React component with the same props.
Keep the set small. Ten well-built components beat forty near-duplicates. If two components differ only in padding, they are probably one component with a size option. We do the same when we start a design system in an MVP design sprint: a small set of parts, built carefully, that the first screens use.
Tokens
Tokens are named values for color, type, spacing, radius and shadow. Instead of a hex code, a component uses color.text.primary. Instead of 16px, it uses space.4.
In Figma, use variables and styles for this. In code, they become CSS custom properties or a theme file. The names should line up. If someone changes the primary color in one place, both the design file and the product should update from that one change.
Two habits help:
- Never use a raw value in a component. If a color is not a token, make it one or do not use it.
- Name by purpose, not by value.
color.dangersurvives a rebrand.color.red-500as the only name does not tell anyone what it is for.
Tokens are a big enough topic for their own article, and we have written one on design tokens for product teams. For handoff, the key point is that tokens are the part of the design that is easiest to translate into code exactly.
States and edge cases
This is where most rebuilds start. The developer reaches a case that was never drawn, and has to guess.
For every screen that loads data or takes input, draw at least:
- Loading. Skeleton, spinner or nothing? For how long?
- Empty. What does a new user see before there is any data?
- Error. What does the message say? Can the user retry?
- Long content. A name with 60 characters. A table with 500 rows. Does it wrap, truncate or scroll?
- Permissions. What does a read-only user see?
- Small screens. What happens at phone width, even if phones are not your main use?
You do not need pixel-perfect art for each one. A rough frame with a short note is enough, as long as it exists. A developer who sees "empty state: show this illustration and this button" builds it in minutes. A developer who sees nothing builds something different, and you find out later.
Add short notes where behavior is not obvious: what happens on submit, what is saved automatically, what needs a confirmation. A sentence next to the frame is better than a meeting.
Reviewing the build
Handoff does not end when the file is shared. It ends when the built version matches what was meant.
A review loop that works:
- Review early, on a staging link. Do not wait for the full feature. Check the first component or screen as soon as it exists.
- Use a short checklist. Spacing, type, color tokens, states, keyboard focus, a narrow screen. Ten minutes per screen is enough.
- Log differences in one place. Screenshots with a one-line note. Mark each as "must fix" or "later".
- Fix the system, not only the screen. If three screens have the wrong spacing, the component is probably wrong. Fix it once.
- Update Figma when the code is right. Sometimes the developer finds a better solution. Then the file should change, so the two do not drift apart.
Our Design Partner plan can include a front-end engineer, which makes this loop shorter because the same team designs and builds. If your engineers are separate, a weekly 20-minute review call does a similar job.
Some of the tools we make for ourselves live in our Lab. UIXport, for example, is a Figma plugin for exporting assets and handoff files, built because we kept doing that work by hand.
What to do on your next project
You do not need to fix everything at once. Pick two things: agree on names in the first week, and draw loading, empty and error states for every data screen. Those two changes remove most of the rework we see.
If you want to know where your current handoff loses time, send us one flow through /contact and we will look at it in a free design review.



