The design was approved. Everyone was happy. Then the build shipped, and it looked like a cousin of the design rather than the design — spacing slightly off, three shades of the same blue, an empty state nobody had drawn, and a form that behaved differently from the prototype.
This is not carelessness on the development side. It is the predictable result of a handoff that answered "what should this look like?" without answering "what should this do in every state at every width?" Here are the five gaps that cause it.
Gap 1 — Only the happy path was designed
Mockups typically show a screen full of perfect content: exactly six items, names of pleasant length, every image present, nothing loading, nothing broken.
Real software spends a lot of its life in the other states. Every meaningful screen has at least six:
- Empty — first use, nothing created yet. Often the most important screen in the product and the least frequently designed.
- Loading — skeleton, spinner, or optimistic render. Undesigned, this becomes a blank flash.
- Partial — some data arrived, some did not.
- Error — what failed, and what can the user do about it?
- Overflow — a name three times longer than the mockup's, 400 rows instead of 6.
- Permission-limited — a user who cannot see or do everything the design assumes.
When these are not designed, developers invent them under deadline pressure. The invented versions are inconsistent because six different people invented them separately.
Gap 2 — Values instead of tokens
A design file with a hex value picked per screen produces a codebase with a hex value written per component. Six months later there are eleven near-identical greys and a rebrand becomes a search-and-replace across hundreds of files.
Named tokens fix this. Not #3533CD but color-primary. Not 24px but space-6. The design file and the code share the same vocabulary, and a change to the token propagates everywhere it should.
The minimum useful token set is small: a colour scale with semantic aliases, a spacing scale, a type scale, radii, shadows, and breakpoints. That is one afternoon of work that pays back for the life of the product.
Gap 3 — Two widths designed, every width shipped
Designs typically arrive at a desktop width and a phone width. Browsers do not stop at those two. The tablet range, the small phone, and the large desktop all get invented by whoever writes the CSS.
The fix does not require designing every width. It requires stating the rules: which breakpoints exist, how each layout reflows at each one, what the minimum supported width is, and — for anything non-obvious like tables, multi-column forms, or dense dashboards — an actual drawn intermediate state.
Gap 4 — No rules for real content
Mockups contain content chosen to fit. Production contains content typed by users.
Specify the constraints explicitly: maximum characters before truncation, whether truncation is ellipsis or wrap, what happens with two lines versus five, minimum and maximum image aspect ratios, how numbers and currency and dates are formatted, and what placeholder appears when an avatar or image is missing.
These decisions get made either once by a designer or repeatedly and inconsistently by developers. There is no third option.
Gap 5 — Interactions described in adjectives
"Smooth transition" and "subtle hover" are not specifications. Two developers will implement them differently, and both will be defensible.
Specify: duration in milliseconds, easing curve, what triggers it, what happens on interruption, and what happens for users who have requested reduced motion — an accessibility requirement, not a nicety. Same for focus states, disabled states, tap feedback, and validation timing. If it can be reinterpreted, it will be.
A design specification is finished when a developer can build it without asking a question, and when two developers building it separately would produce the same result.
What a design system actually is
The phrase intimidates small teams into thinking it means a year of work and a dedicated team. For a product-sized team it means four things:
- Tokens — the named values above, shared between design tool and codebase.
- Components — every state of every reusable element drawn once: default, hover, focus, active, disabled, loading, error. Buttons, inputs, selects, cards, modals, tables, toasts. That is most of an application.
- Patterns — how components combine for recurring situations: form layout, page header, empty state, destructive confirmation.
- Rules — the written decisions: content limits, breakpoint behaviour, motion, accessibility baseline.
Built as you go, alongside the first real screens, this is a couple of weeks of work rather than a separate project — and it removes the majority of handoff ambiguity permanently.
Test before you build, because that is where changes are cheap
A change costs almost nothing in a design file, a day in a prototype, a week in a built feature, and considerably more once it is live and users have learned the old behaviour. That gradient is the entire argument for prototyping and usability testing.
The version that fits a real budget: build a clickable prototype of your two or three most important flows, put it in front of five people who resemble your actual users, ask them to complete a task, and stay quiet while they try. Five people surface most of the serious problems. It takes a few days and routinely prevents a rebuild.
Accessibility is part of the design, not a later audit
Retrofitting accessibility is expensive; designing for it is nearly free. Check contrast ratios while choosing colours. Never encode meaning in colour alone. Design visible focus states rather than leaving them to the browser. Keep tap targets adequately sized. Specify heading hierarchy and alt text expectations. Provide a reduced-motion path for anything animated.
The same choices that make a product usable with assistive technology make it more usable in bright sunlight, on a bad connection, and for anyone in a hurry.
What good handoff looks like
A developer opens the design and finds: tokens they can map directly to code, every component state drawn, breakpoint rules written down, content limits stated, interactions specified in numbers, and a prototype showing the intended flow. They build it without a single clarifying message, and the result matches.
That is the entire goal. Everything above is in service of it — and it is what our UI/UX & Product Design service is built to deliver: designs that survive contact with real code.
