Analyze with AI
Get AI-powered insights from this Mad Devs article:
A shared component changes once in a design file, yet the live product still requires fixes in several independent implementations. That symptom matters to a Head of Product or Head of Engineering because every apparently small UI change can reopen design, frontend, and acceptance work.
A design system is the maintained agreement that connects interface decisions, reusable code, usage guidance, and ownership. It includes a component library, but is not limited to one. This guide explains how to create a design system for a working product without detaching the effort from the feature roadmap. The outcome is a bounded first scope, an implementation approach, acceptance evidence, and clear responsibility for what happens next.
Key takeaways
- A viable first release solves one repeated product problem within an explicitly limited scope.
- Design assets and frontend components need a traceable shared contract, including states and responsive behavior.
- Acceptance combines measurable design checks, accessibility and behavior tests, and validation of the complete user flow.
- A named owner must manage changes, exceptions, migration guidance, and the effect on consuming pages.
Decide what the first version needs to solve
Start with a decision, not a component inventory. The Head of Product should identify the recurring product problem, while the frontend and design leads establish where it appears and what already exists. Record the affected product, platforms, repeated patterns, live components, design assets, known defects, and the person who can decide whether a shared contract changes.
The first scope should be narrow enough to release through a real user flow. A cosmetic inconsistency seen once may need a local fix. Repeated validation behavior across settings screens is a stronger candidate because one decision can remove competing implementations.
The intervention depends on the assets and constraints you find. Figma's guidance recommends auditing existing interface and code assets before deciding whether to adopt, adapt, or build. Use the following matrix to choose the smallest credible change.
| Situation | Approach | Extent of change | Limitation |
|---|---|---|---|
| Useful shared components exist, but variants and usage have drifted | Consolidate and improve the existing library | Align naming, states, APIs, documentation, and selected consumers | Does not fix patterns that were never represented in the library |
| Product needs are mostly covered by a maintained external system | Adapt an existing system | Map foundations, theme it, wrap components where necessary, and migrate the chosen flow | Product-specific behavior and upgrade constraints still require ownership |
| A repeated flow has behavior or brand requirements that available components cannot support | Build the required custom components | Create only the foundations and components needed for the first release | Creates a maintenance obligation and should not become a pretext for rebuilding every screen |
Whichever route is chosen, write a one-sentence problem statement and name the decision owner. For example: “The first release will make form fields and validation messages consistent across two settings screens; the Frontend Lead owns the code contract.” It gives the Product Owner a scope boundary for backlog requests.
Create the first version around a real product flow
Creating a design system for an existing product is an implementation sequence: inspect the live experience and code, establish usable foundations, complete component behavior, document the contract, and release one slice. The selected flow keeps each decision connected to product behavior rather than an abstract library backlog.
Audit the live interface and the code together
The design lead and frontend lead should review the same product area at the same time. A design-only inventory misses behavior embedded in code. A code-only inventory can preserve differences that no longer serve the product.
For each repeated pattern, capture its purpose, locations, variants, states, real content, and implementation. Compare that record with the current design assets. Note whether the same-looking elements perform different jobs. A compact button that submits a form and one that opens a menu may share visual foundations while requiring different semantics, keyboard behavior, and APIs.
Map dependencies: local, copied, shared-package, or multi-application components. Record framework constraints so the Frontend Lead can estimate the blast radius.
End the audit with a disposition for every item in the selected area:
- Keep: the current design and implementation already meet the agreed contract.
- Replace: a shared component can remove a repeated inconsistency in this release.
- Defer: the item is real, but changing it would expand the flow or dependency risk.
- Separate: visual similarity hides a different purpose, so it should not share one component API.
The output is a bounded first-release list linked to the live interface, design file, and repository.
Define foundations and tokens that implementation can use
Foundations turn recurring visual decisions into roles that design and code can apply consistently. Define only what the chosen flow needs: semantic colors, typography roles, spacing, themes, and responsive constraints. A token such as color.text.danger expresses the role of error text; red-600 only describes a palette position. The semantic name lets a theme change without rewriting the component's purpose.
Decide where each class of decision originates and how it travels. For example, design may propose a semantic role, design and engineering approve its meaning, and the code repository stores the released token representation consumed by components. If Figma and code both contain editable copies with no update path, neither is a dependable source of truth.
Responsive constraints belong in this contract. Specify what wraps, collapses, reorders, or changes density at the widths used by the product. A spacing token cannot explain that behavior on its own. Themes need the same treatment: test semantic roles in each supported theme rather than assuming that swapping color values preserves contrast and state recognition.
This is where product UI/UX design and frontend implementation meet. The useful deliverable is a small, reviewed set of roles that designers can select and components can consume, plus a documented change path.
Build components with complete behavior and states
Select components required by the first flow, not the components that are easiest to showcase. For a settings flow, that may mean fields, labels, validation messages, toggles, buttons, and an inline notification. Implement them against real content and the existing frontend framework.
Define the component contract before migrating screens. It should cover variants, loading, error, disabled, hover, focus, and selected states where applicable. Specify keyboard interaction, focus order, content limits, and responsive changes. A field that looks correct with “Name” may fail with a long translated label or a server error. A button API that accepts every arbitrary style may simply reproduce the inconsistency under a shared import path.
Keep product rules outside general UI primitives. A shared field can expose error and help text; it should not decide whether an account email can be changed. The consuming feature owns that rule. This boundary makes the component reusable without hiding business behavior from the product code.
Fit the API to the framework already in use. Reuse established form state, routing, and styling conventions where they remain sound. If adoption requires replacing those foundations, expose that as migration scope rather than disguising it as component work. Test the shared behavior at the component level, then test it again in the consuming flow because composition can change focus, layout, and state handling.
Document usage and assign change ownership
Documentation should help a designer or developer make the next decision without reverse-engineering an example screen. For each released component, state its purpose, supported variants and states, content constraints, accessibility expectations, and cases where another pattern is preferable. Link design assets to the implemented API and identify the released version.
Assign ownership at the level where a change has consequences. Design and engineering jointly approve changes to a shared visual or behavioral contract. Product decides whether the work enters the roadmap and which flows are in scope. A named maintainer handles issue routing, releases, and migration notes. “The team owns it” is not enough when a feature deadline conflicts with a shared change.
Versioning communicates impact. A backward-compatible state can ship with an ordinary release and an adoption note. A removed property or changed behavior needs an explicit migration path, affected consumers, and a removal decision. Document exceptions with a reason and owner instead of allowing silent forks. Governance here is deliberately small: enough to keep the released slice usable, without creating a separate committee before value has been demonstrated.
Integrate and release one usable slice
Apply the new contract to the chosen flow and let old and new elements coexist elsewhere. This is normal during adoption. The Frontend Lead should identify shared dependencies, sequence replacements so the flow stays operable, and avoid a product-wide switch in one release.
Integration exposes issues a component workbench cannot: inherited styles, layout, validation timing, analytics, routing, and server responses. Run the scenario with realistic data and required states. Check downstream pages when a change modifies a shared dependency.
The first version is ready only when four things exist together: an implemented user scenario, usage documentation, acceptance evidence, and a named maintenance owner. A Figma library without a consuming release is a design asset. A code package without rules and ownership is a component library. Both may be useful inputs, but neither alone proves that the design system works in the product.
Keep the release review tied to the initial problem statement. If the two settings screens now use the agreed behavior and pass acceptance, release them even if the audit discovered unrelated navigation drift. Put the deferred items into a visible backlog with reasons. That protects the feature roadmap while preserving evidence for the next scope decision.
Verify that implementation follows the system
Acceptance needs three separate kinds of evidence because none can substitute for the others.
- Design conformance: Do mapped elements use the agreed dimensions, spacing, typography, and colors at the specified widths and states?
- Behavior and accessibility: Do focus, keyboard operation, semantics, contrast, errors, and responsive behavior work for users?
- Flow correctness: Can a user complete the scenario, and do data, permissions, validation, and failure handling behave correctly?
Mad Devs has published figma-to-code-pixel-perfect, an open implementation of part of the first question. Its workflow snapshots selected Figma frames, produces readable specifications, maps Figma nodes to selectors, compares measurable properties, checks coverage, and requires visual review with recorded exceptions. This is design-to-code verification, not a claim that a whole product is “pixel-perfect.”
The mapping makes acceptance traceable. A reviewer can see which node corresponds to which rendered element and whether properties such as font size, spacing, or dimensions fall within configured tolerances. Coverage checks require mapped or explicitly ignored text sections and styles. PASS, WARN, PENDING, and SKIP have different meanings; in strict mode, WARN and PENDING also fail the check, while SKIP remains a documented exception. Treat the mapped frame, viewport, and state as the unit of evidence. A result for an idle desktop state cannot be reused as evidence for mobile, loading, or error states.
The limits matter. The published workflow says image content, SVG shapes, borders, shadows, gradients, and anything unmapped are not measured. Those require visual review or another suitable check. Each required width and state must be represented explicitly; one desktop result does not prove responsive correctness. A passing property comparison also does not prove keyboard access, accessible semantics, or successful saving of settings.
Use automated comparisons as one evidence stream in a broader UI testing plan. Record the tested frame, viewport, state, mapping, exceptions, and reviewer. Then run accessibility checks and the actual user flow separately. Acceptance is credible when the evidence states both what was checked and what remains outside the check.
Roll out without losing ownership of the product
Expand from the first flow according to reuse, change cost, and user risk. A component used on six low-risk internal screens may be a better next migration than one used once in a revenue-critical journey. The Product Owner sets the order; engineering supplies dependency and release risk; design identifies where the shared contract genuinely applies.
For every shared change, list consuming pages and rerun proportionate checks. A harmless default spacing change can alter dense tables elsewhere. A new validation API can change when errors appear. The owner should decide whether consumers migrate together, receive a compatibility period, or stay on an explicitly supported older version.
One responsibility pattern in the published Mad Devs project keeps page-building work from changing shared components autonomously. The builder records shared proposals for review instead. That is one practical separation between delivery and system ownership, not a universal organization chart.
Track adoption within the agreed scope, not across an imagined perfect product. Useful measures are the proportion of scoped UI using accepted components, repeated correction requests, lead time for comparable UI changes, and the number and age of exceptions. Trends prompt investigation; they do not by themselves prove causation or savings.
Mad Devs also describes design-library improvements in a mobile banking product, including a dark theme and synchronization with iOS and Android. This is relevant delivery evidence, but it should not be treated as proof that the open verification project was used there or that a particular outcome came from the design system alone.
Example: a first design-system release for account settings
Illustrative example – not a client case or measured benchmark. An existing SaaS product has separate account settings and notification settings screens. They use different field spacing, button variants, and validation messages even though both ask users to edit and save preferences.
The Head of Product limits the first release to these two screens. Design and engineering audit the live UI, files, and code, then keep the existing layout. They exclude global navigation, billing, profile onboarding, and a new application-wide grid. The selected foundations cover semantic text and status colors, typography roles, form spacing, and the supported responsive widths. The component set covers the fields, labels, validation messages, toggles, and primary and secondary actions required by the two screens.
The audit finds that both screens need an inline validation message, but one implementation renders it at 14px while the accepted design role specifies 16px. Engineering creates one shared message component with error semantics and documented content constraints, then applies it to both screens. A node-to-selector check compares the font size in the defined error state and reports the original mismatch. After correction, the reviewer records the mapped property result and visually reviews the screens.
Separate checks confirm keyboard and focus behavior. Flow tests confirm that valid settings save, server errors remain visible, and existing preferences are not lost. The Frontend Lead accepts the code contract with the Design Lead; the Product Owner confirms that the two-screen scope is complete.
Accepted deliverables are the implemented screens, necessary tokens and components, usage guidance, test evidence, exceptions, and named maintainer. Billing and onboarding remain in the backlog pending a reuse and risk assessment. No time-saving percentage is inferred from this first release.
Choose who will deliver and maintain the system
The right delivery model depends on ownership, capacity, and dependency risk rather than on whether creating a design system is theoretically possible in-house.
An in-house approach fits when a named owner can make cross-feature decisions, frontend and design capacity is available, and the first scope is already constrained. The internal group should still agree on acceptance evidence and protect maintenance capacity after the initial release.
Specialist support can close a defined gap such as component implementation, integration with an existing framework, migration of one flow, accessibility work, or design-to-code acceptance. The client retains product decisions while the specialist delivers a bounded technical outcome.
A joint delivery scope is useful when audit, component work, integration, testing, release preparation, and handover depend on one another but internal capacity cannot carry all of them. Agree which decisions stay with the Product Owner, Design Lead, and Frontend Lead. The discussion can cover an asset and discrepancy map, bounded implementation scope, implemented components and integration, checks, documentation, and handover.
These are examples of negotiable frontend development for an existing product, not a fixed package. Self-delivery remains a valid option. External work is valuable when it produces maintainable changes in the live context, not access to public instructions or a hidden installation step.
Conclusion
Choose one repeated user scenario before expanding the component backlog. Name the product, design, and engineering decision owners, then write the acceptance criterion in terms of a working flow and explicit evidence. That gives the first release a finish line. Once it is operating in the product, use adoption, exceptions, change cost, and risk to decide where the system should go next.
Frontend Development Make your design system work in production Connect shared components to your live frontend, release workflow, and acceptance checks. Discuss your scopeCome with a selected product flow, the design and code assets you already have, and one known constraint. |






