Building a design system your developers actually use

Building a design system your developers actually use
By Marco Lopes · October 24, 2022 · Design, 3D & XR
A design system can look convincing in a presentation and still disappear when development starts. We can organise a beautiful component library, name every colour, and document a spacing scale, yet watch production interfaces drift away from it.
The problem usually is not that developers dislike consistency. It is that the system costs more effort to use than the alternatives. Its components miss real requirements, its documentation leaves unanswered questions, or its release process makes a small improvement feel like a separate project.
At Kordspace, we approach this as a collaboration problem as much as a design problem. As a remote studio working across software, AI, Web3, hardware, and design, we need shared decisions that survive different tools and technical constraints. A useful design system makes those decisions easier to apply, not merely easier to admire.
Start with delivery problems, not a component inventory
Before drawing another button, we should identify where the team loses time. Are forms rebuilt for every feature? Do designers repeatedly explain the same responsive behaviour? Are engineers guessing which grey belongs to disabled text?
We can review a few representative screens alongside their implementation and list the recurring disagreements. That gives us a starting backlog grounded in actual work.
For an initial release, we should choose a narrow product journey: signing in, completing a form, or reviewing an account. It should contain enough variation to expose real requirements without turning into a redesign of the entire product.
We can then define success in observable terms. Can another developer complete the journey without inventing new styles? Can a designer explain an exception without a private message? These questions are more useful than counting components.
Treat the system as a product
Developers and designers are users of the design system. That means we need to understand their tasks, remove friction, and respond when the product does not work for them.
A Figma library and a package of UI components are useful artefacts, but neither is the whole system. We also need principles, usage guidance, ownership, and a route for changing things.
We should make a few responsibilities explicit:
- Who reviews visual and interaction decisions?
- Who maintains the implementation and publishes releases?
- Where do questions and proposed changes go?
- Who decides whether a pattern belongs in the shared library?
These responsibilities do not require a large dedicated team. One designer and one engineer can provide a starting point. What matters is that ownership is visible and maintenance is planned, rather than assumed to happen between deadlines.
Establish a small, meaningful token layer
Design tokens give us named values for shared decisions: colour, typography, spacing, shape, elevation, and motion. They become useful when their names communicate purpose.
A primitive such as blue-600 describes a palette entry. A semantic token such as color-action-primary describes a role. We usually want both, with components depending on semantic roles wherever possible.
That separation lets us change a theme without asking every component to understand the palette. It also makes reviews clearer: we can discuss whether something is a primary action instead of debating a hex value.
We should keep the first token set small and grounded in existing needs. JSON transformed into CSS custom properties or platform-specific values can be enough; tools such as Style Dictionary can help when multiple outputs are necessary.
We also need to document which representation is authoritative and how changes reach design files and code. Two independently maintained sources quickly become two conflicting systems.
Design component APIs with developers
A component's API is part of its design. If its properties are confusing, or if normal product requirements demand custom CSS, adoption will suffer even when the default appearance is excellent.
We should work through real examples together before finalising the interface. For a button, that means more than size and colour. We need to discuss loading behaviour, disabled behaviour, icon placement, accessible naming, and the distinction between an action and navigation.
We should prefer a small set of meaningful variants over a collection of unrelated switches. A component with many boolean properties can permit combinations that nobody has designed or tested.
At the same time, we should avoid solving every hypothetical future requirement. Composition often provides a better escape route than dozens of configuration options. We can expose stable building blocks, explain their boundaries, and add abstractions when repeated use demonstrates a need.
Specify behaviour, not just appearance
A static frame cannot tell us everything required to build an interface. We need to describe what happens before data arrives, when content is missing, after a request fails, and when text exceeds the available space.
For each component, we should capture the relevant interaction states and content constraints. A text field, for example, needs guidance for labels, help text, validation, focus, disabled states, and error recovery, not simply an attractive empty state.
Responsive behaviour deserves the same attention. We should explain what grows, wraps, disappears, or changes arrangement, rather than handing over three screenshots and leaving the transitions to guesswork.
For remote collaboration, these decisions should live beside the component. A short recorded walkthrough can help explain intent, but durable written guidance and runnable examples should remain available after the meeting and across time zones.
Build accessibility into the foundation
Shared components let us solve recurring accessibility problems once, but they can also spread mistakes widely. We should treat accessibility as part of a component's acceptance criteria, not as a polish pass.
That includes semantic HTML, keyboard operation, visible focus, appropriate contrast, understandable labels, and predictable focus management. Dialogs and menus deserve particular care because their behaviour is more complex than their appearance suggests.
We should test with keyboards and screen readers as well as automated tools. Automated checks catch some issues; they do not establish that an interaction is understandable or usable.
We also need to document what remains the consuming team's responsibility. An accessible input component cannot guarantee that its label is meaningful. A colour token cannot guarantee contrast against every background. The system should make the right choice easier while clearly explaining its limits.
Put documentation beside working code
Developers should be able to move from a question to a working implementation without searching through several disconnected tools. A component workshop such as Storybook can bring examples, controls, and usage notes together.
For each component, we should include a short purpose statement, common examples, relevant states, API guidance, and known limitations. We should also explain when not to use it. That prevents a flexible component from becoming the answer to every unrelated problem.
Examples should reflect production conditions. We can show long labels, empty results, failed requests, and translated text instead of only ideal content.
Installation matters too. We should provide an accurate quick start, including required styles, providers, supported framework versions, and any assumptions about rendering. A polished documentation site does not compensate for a first example that fails to run.
Make the supported path the easiest path
Adoption improves when the shared component is easier to reach for than a local replacement. We should make imports predictable, package names clear, and starter projects consistent with the documented setup.
Changes should flow through familiar development tools: pull requests, automated checks, preview builds, and versioned releases. Google Cloud can host documentation and previews where it fits the project; AWS or Azure can serve the same role when those environments are already established. The infrastructure should support the workflow, not dictate the design system.
We should test more than compilation. Depending on the component, we may need interaction tests, accessibility checks, visual regression checks, and a representative consuming application.
Versioning and migration notes are equally important. If an update changes behaviour, we need to explain the change and provide a practical migration path. Surprise breakage teaches teams to stop updating.
Extend principles carefully into 3D and XR
For 3D and XR work, we should not assume that a web component library can simply be placed into a scene. Spatial interfaces introduce viewing distance, scale, occlusion, input differences, and comfort considerations.
Some foundations still transfer: semantic colour roles, typography intent, content hierarchy, and feedback principles. Others need adaptation. A CSS pixel spacing scale is not automatically a useful spatial layout system, and a hover interaction is not a dependable basis for controller or gaze input.
We should document supported interaction modes and test in the target environment. A scene preview on a laptop cannot establish that text is readable or controls are comfortable in a headset.
Motion guidance also needs context. We can define purposeful transitions and reduced-motion alternatives without demanding identical animation across every platform. The goal is a coherent experience, not matching implementations at the expense of usability or comfort.
Create a contribution path, not a gatekeeping process
A shared system needs boundaries, but it should not become a queue that blocks delivery. We should provide a lightweight proposal format covering the problem, existing alternatives, expected reuse, and an example implementation.
Not every new pattern belongs in the core library. We can keep product-specific experiments local until their behaviour settles and repeated demand becomes clear. That protects the shared API from premature assumptions.
When an exception is necessary, we should record why it exists and when to revisit it. An explicit exception is easier to manage than a hidden fork.
We should also distinguish urgent fixes from broader design changes. Correcting broken keyboard behaviour should not require the same discussion as introducing a new navigation model. Clear review paths let us protect quality without making contribution exhausting.
A short checklist before we expand
Before adding another family of components, we should check the foundation:
- Can a developer install the library and run a documented example?
- Do design and code share meaningful names and an explicit update process?
- Are common states, responsive behaviour, and accessibility expectations documented?
- Have we tested the components in a real product journey?
- Are releases versioned, with useful change and migration notes?
- Can the team report a gap or propose an exception without blocking delivery?
If several answers are no, expanding the catalogue is unlikely to solve the underlying problem. We should improve the existing experience first.
Earn adoption through everyday usefulness
We cannot declare a design system successful because it exists. We need to see it helping people ship: fewer repeated decisions, clearer reviews, easier onboarding, and less need to work around shared components. We should keep listening to the teams using it and treat recurring workarounds as feedback, not disobedience.
If we can help connect your design foundations with dependable implementation, across web software, connected hardware, or spatial experiences, we would welcome the conversation. Start a project with Kordspace, or explore our related services to see where we can work together.
Conversation (0)
No comments yet. Start the conversation.
Join the conversation
Create a free member account to comment.