Design handoff to engineering: what actually breaks?
Handoff is the wrong word, and the projects that use it seriously are the ones with the most rework. Nothing is handed over: the design is a proposal until an engineer has built it, discovered what the API actually returns, and found the four situations nobody drew. Treating the design file as a finished specification produces a product that resembles it on the happy path and improvises everywhere else, which is where most of the daily experience lives.
What actually gets lost between design and code?
The states nobody designed. Loading, empty, error, partial, permission denied, offline, too much content, too little content, the item with no image, the name that is too long, the list with one entry and the list with nine hundred. Every one of these gets built by somebody, and if it is not in the design it gets invented under time pressure by an engineer who has ten minutes.
Second, behaviour over time: what happens while a request is in flight, what happens if it fails, whether the failure is retried silently, what the user sees if they navigate away and back. Static designs represent moments, and products are made of transitions between moments.
Third, the reasoning. A specification says the confirmation step is two clicks; it rarely says why, so the first person to optimise the flow removes it. Non-obvious decisions need one line of rationale attached, and this is the cheapest documentation in the discipline and the most reliably skipped.
What should a specification actually contain?
Less measurement and more behaviour than most teams produce. If tokens and components exist, spacing and colour are already settled and re-specifying them per screen wastes everyone's time. What cannot be inferred from the file is the conditional logic, and that is what the specification is for.
The workable minimum per flow is a list: every state with its trigger, what the user can do in each, what happens on failure, what data the screen depends on and what to show when it is missing, and the validation rules with their exact messages. Written as prose or a table, not as more screens.
Error message wording deserves particular attention because it is the part most often left to engineers, and generic messages are one of the clearest signals of an unloved product. If a designer specifies nothing else in writing, specifying the actual text of the failure cases is the highest-value thing they can do.
| What is handed over | Usually specified? | Who ends up deciding | Cost of getting it wrong |
|---|---|---|---|
| Happy path layout | Yes, in detail | Designer | Low, it gets reviewed |
| Empty and loading states | Often not | Engineer, at speed | High, users meet these on day one |
| Error and validation wording | Rarely | Engineer or the backend's default message | High, and very visible |
| Behaviour under real data volume | Almost never | Nobody, until support reports it | High, and expensive to fix late |
| Keyboard order and focus behaviour | Rarely | The framework's default | High, this is where accessibility fails |
| Exact spacing values | Almost always | Designer | Low, if tokens exist |
Why does the built version drift from the design?
Because the design was never checked against reality, and the checking happens in code. An engineer discovers the API returns nothing for a field the design assumed, or that the sorted list arrives unsorted, or that the operation takes four seconds rather than the instant the mock-up implies. Each discovery forces a local decision, and local decisions accumulate into a different product.
The fix is not more detailed files, it is earlier contact. A designer who sees the real API response before finalising a screen designs for the data that exists. Half an hour with an engineer at the start prevents more drift than a week of annotation at the end.
The other structural cause is designers who never look at the built result. Design work is commonly considered done when the file is delivered, so nobody compares the running product to the intent until a user complains. Reviewing the built version should be a standing part of the work, and it is the single change that most improves output quality on teams that do not do it.
Who should own the built result?
Somebody, explicitly, and it does not much matter who. The common failure is that the designer considers it engineering's implementation and engineering considers it the designer's design, so the gap between them belongs to neither. Naming an owner for the built experience closes it, whether that is a designer with codebase access, a design engineer, or an engineer with an eye for it.
Where a design engineer exists, this is their real value: they hold both sides and can fix a spacing error in the component rather than filing a ticket that waits three sprints. On teams without one, the practical substitute is giving the designer permission and enough access to raise small corrections directly.
Avoid the pixel-perfect audit as a mechanism. Long lists of two-pixel discrepancies exhaust goodwill and crowd out the corrections that matter, which are usually about states and behaviour rather than geometry. Report what a user would notice.
What check can you run this afternoon?
Open your product and try to reach four states without touching the design file: a screen with no data, a screen while it is loading, a screen after a failed request, and a screen with an unusually long name or an unusually large list. Then look for the same four states in the design. The gap you find is your handover problem, and it is nearly always larger than expected.
Then unplug the mouse and complete one core task with the keyboard alone. Where the focus disappears, or a dialogue traps you, or the order jumps around, you are looking at behaviour that was never designed and was therefore inherited from a framework default.
Both checks take twenty minutes and neither requires design skill. If they are clean, your handover process is working better than most. If they are not, the fix is a specification convention and a review habit rather than a new tool.
Common questions
- What breaks during design handoff to engineering?
- The states nobody designed: loading, empty, error, partial, permission denied, offline, and content that is much longer or much larger than the mock-up assumed. Every one of these gets built by someone, and when it is missing from the design it is invented under time pressure. Behaviour over time and the reasoning behind non-obvious decisions are the other two things that routinely fail to survive the transition.
- What should a design specification include?
- Behaviour rather than measurements. Per flow, list every state with its trigger, what the user can do in each, what happens on failure, what data the screen depends on and what to show when it is missing, plus validation rules with their exact message text. If design tokens and components exist, re-specifying spacing and colour per screen adds nothing, since those are already settled.
- Why does the built product look different from the design?
- Because reality is discovered in code. An engineer finds that the API returns nothing for an assumed field, that a list arrives unsorted, or that an operation takes seconds rather than appearing instantly, and each discovery forces a local decision. Earlier contact fixes more of this than detailed annotation: a designer who sees real API responses before finalising screens designs for the data that exists.
- Who owns the built experience, design or engineering?
- Whoever is named, and the failure is leaving it unnamed so that the gap belongs to neither. A design engineer holds both sides and can correct a component directly rather than filing a ticket. Without one, give the designer access and permission to raise small corrections, and make reviewing the running product a standing part of the work rather than something that happens when a user complains.
- How do you check whether handoff worked?
- Reach four states in the running product without consulting the design file: no data, loading, after a failed request, and with unusually long content or a very large list. Compare each against what the design specified. Then unplug the mouse and complete one core task by keyboard alone, watching for lost focus, trapping dialogues and jumping order. Both checks take about twenty minutes and need no design skill.