Design system contracts: the component lives in neither Figma nor code

One source of truth in the middle, two copies that stay honest, and why AI makes it urgent.

A design system exists twice at once. It is in Figma as components, and it is in code as the real thing engineers ship. Those two are supposed to be the same. They never quite stay that way.

You change a button in one place. Someone forgets to change it in the other, and they slowly drift apart. A few weeks later, a designer builds a screen with the old button, an engineer builds it with the new one, and the review turns into an argument about which file is right. You have been in this discussion, so have I.

I want to show you a way out of that argument. It is not my idea, and it is not new. Nathan Curtis has been working on this for the past few years, describing components as plain data, and his article Components as Data is probably the deepest write-up. Southleft, a design systems consultancy (founded by TJ Petri, who just joined Figma), recently published their repo building on the same concept, along with a small concept playground you can open in a browser and break your component in a minute (I love breaking things, that is when it clicks). They call it a design system contract. Let’s explore this as designers:

The problem, said plainly

Most teams try to fix drift by picking a winner. Either the code is the real system, and Figma has to chase it, or Figma is the real system, and code has to chase it.

It does not matter which one you pick. Whichever you crown, the other becomes a copy that someone has to keep updating. That is not a discipline problem you can train away. It is just what happens when the same thing has to be maintained in two places by two different people (and there are whole books about how to deal with it, so I will cut it short here).

The idea: the contract

Instead of treating Figma or code as the real one, you put a third thing in the middle. For each component, we will use a small file; we will stick with the word “contract”. This could be a JSON or YAML file per component, and you can look at an example in the repo right here. If you are a designer and do not know what JSON and YAML are, don’t worry, I’ve got you covered. Keep reading.

JSON component contract example by Southleft.

So this file is basically just a plain description of the component. What options does it have, like a button being primary or secondary? What colours and tokens does it use? What is allowed inside it? What does it do when you click it? If you look closely at the image above, you can see how, in this case, it also maps to Figma (it does not have to; it could also just stay in code). No pictures, no code, simply the agreement about what the component is.

Then the part that flips it round. Both the Figma version and the code version get built automatically from that one little file. On the code side the files are written straight out. On the Figma side the contract becomes a set of instructions that a small plugin runs inside your file to build the components. Neither is the original. They are both printouts of the same recipe.

And there is a checker you can run that compares all three: the contract, the Figma library, and the code, and tells you exactly where they have stopped matching. It is a check you run, or let your pipeline run for you, not an alarm that pops up on its own.

So a button’s status option is written once. In Figma, it turns into a set of variants. In code, it turns into a typed option.

Same source, two faithful copies, and something that catches the exact moment they stop agreeing.

📝 Personal note: I would love a design tool to solve this more elegantly, so that we do not use variants for pseudo-classes, e.g. hover and active are just values on a state prop, yet in Figma we have to set them up as variants. Another article entirely.

Note: Why JSON or YAML and not MD files?

Now, if you get this one, you get the concept: Why JSON or YAML, you might ask, when everything these days is an LLM reading a markdown file? Because JSON or YAML are text files where everything has a label. A form with boxes, not a paragraph.

A markdown file has to be understood, and understanding varies. But a contract only has to match, and matching is deterministic and needs same file in, same answer out, every time.

JSON or md?

So a computer can check the boxes against Figma and against code and tell you exactly where they stopped agreeing. With a paragraph, it can only be read and interpreted, and that is where drift creeps back in.

Go and click around

Nothing beats hands-on, so go and dig in. There is a browser playground that runs the real engine; try it! You can edit a contract and watch both Figma and code rebuild from it, so amazing! You can add your own components or play with the demo, as I did in the video below. You can break a rule on purpose and watch it get refused. You can paste in a Figma link or your own tokens and see what comes out.

browser playground

Play with it here: ds-contracts-playground.pages.dev

The one rule that makes it work

Figma and code are never allowed to update each other directly.

If a designer changes a colour or an engineer adds an option, that change does not jump straight from one side to the other. It goes into the contract first, gets reviewed like any other edit, and then both sides rebuild from it. One source in the middle, and everyone else follows.

This is stricter than how most people work today. Curtis describes going back and forth between Figma and the data, refining in both, and when he authors examples, Figma is the input the data gets read out of. That is a perfectly sensible way to work when a careful human is holding both ends. The contract is betting that once an AI is in the loop, “we go back and forth” stops being a workflow and starts being a hole. Whether that trade is worth it depends on how much of your building is still done by hand.

The part that makes it matter now: agentic design systems

For years, drift was annoying but survivable. You fixed it with process and a patient person keeping the library tidy. Now AI has started to build screens, and the stakes have changed.

When you hand an AI your design system and ask it to build, it does what any unsupervised copy does. It drifts, only faster than a human ever could. In Southleft’s own A/B test, an AI left to its own devices scored 69 out of 100. It invented options that did not exist. It hard-coded colours instead of using your tokens. It restyled components to taste. It made work that looked fine and quietly broke the system in ninety places.

The same AI, handed the contract as a strict rulebook, scored 100 out of 100. And when it hit something the system truly could not do yet, it said so, instead of faking a version that looked complete.

That gap became a proposed change to the contract, the change got reviewed, and the system grew by one honest step.

Now, let me be clear, none of this is mine. The idea, the model, the 69 versus 100 experiment, all of it comes from Southleft. I did not run those tests and I do not work on the dev side of this, I am reading their receipts like you are. Still..

What this means for me as a designer

Here is the part that decides whether I care. When a tool turns my design into code, does it respect the decisions I made, and does it do so over time, or does it hand back the usual mush and (design)drift?

A contract respects them, because the styling is not guessed. Every part of a component is tied to a token I defined. A colour is a named decision, not a stray hex someone picked in a hurry, and when I change the token, both sides move together. That is already a world away from exporting straight out of Figma, where the CSS that falls out was never meant to be shipped in the first place.

I will be honest about the edge of it, though. The contract fixes what a component is made of and which token sits where. It does not decide how the code underneath is actually written, and a lot of craft lives in that layer. The good part is that this last step is separate and swappable, so the day I want the output held to my own standard, that is a piece someone can build without touching the model. Right now, the contract gets the decisions right. The finish is the next thing worth fighting for.

What I would check before believing me

I do not want to oversell, so a few thoughts. What caught my eye is not that the spec builds both sides, that already exists. It is the checker. Style Dictionary has done “one source, many outputs” for years, but only for tokens. Running it at the component level and proving the two copies still match is the part I had not seen.

And it is boring in the right way. Same contract in, same output every time, checked byte for byte against a recorded copy. Nothing is being generated at that step, it is a compiler, not a model, which is exactly why it cannot get creative. That sounds like plumbing until you remember what we usually get, which is a slightly different button every time you ask.

So, a very solid way to fight that drift that is driving us all beyond good and bad. Also note:

It is not Code Connect, and it is not UXPin Merge. Those sync one surface to the other and crown code.

The contract crowns neither, which is the whole point, and as a designer, that is the first version of this I have read that does not quietly put me downstream.

It fixes what a component is made of, not what you can build with it. It can tell an AI a Card takes a header, a body and a footer. It cannot tell it what a good pricing card looks like. That takes worked examples, and they sit beside the contract, not inside it.

Plenty else stays outside the file. Things like drag, typeahead, focus-trapping, motion, and good CSS. That is still hand-written. Accessibility is the exception; ARIA semantics do sit in the contract, which surprised me, in the best way. The thing is that most of it is stuff we can’t design or extract from Figma anyway, so it was already living in someone else’s head. The contract does not fix that, it just makes the gap easier to see.

And it is not free. Hand-built library, legacy code, and this is a migration, not a switch. There is an on-ramp, they can extract proposed contracts out of a library you already have, and they have run it against Shoelace, Mantine, Carbon and Polaris to prove it. It is still a terminal command, not a button. You take on a third artefact and the tooling that keeps it honest. Governance does not vanish, it moves into a review. Calmer, still a human deciding who may change the shared file. If you are the person who currently keeps the library tidy, you are the person who ends up in that review.

One repository, one schema, early days. The idea is the thing to take for now.

So, who is this actually for? And who needs it.

Design systems writing is nearly always written for the very large, and that used to make sense, because only the very large could afford a design system. AI moved that line, and we are all still writing as if it did not. So let me put the three sizes side by side, because the answer is not the one you would expect.

usage

Solo, or a team of three: you do not need this. You are Figma and you are code, both at once, and the two cannot drift apart because there is no handoff between them. A contract would be a third thing to maintain so that two things you already agree on can agree.

Enterprise: this fits, and they will get it first, or already run some version of it. They have a design systems team and someone whose job title actually covers the tooling. They feel the drift too, they can just afford to absorb it, with headcount and a patient person (trying) to keep the library tidy.

Everyone in the middle, and this is the part my heart beats for: twenty people, eighty, two hundred. Big enough that Figma and code have properly drifted. Too small to pay anyone to keep them together. No design systems team, or one person doing it at 20% between product work. Leaning on AI hardest, precisely because there is nobody spare. These are the teams I teach, and they are the ones nobody writes for.

Both need it, the middle and the top. Only one can run it. So it lands with whoever can staff it, which is exactly the wrong way round. That flips the day it stops being a repo and becomes something you install easily.

It is not a fantasy; tokens made that exact trip. Style Dictionary was an enterprise pipeline until Tokens Studio put it in a panel, and then a two-designer team could use it. I remember when that felt out of reach too.

Contracts have not made that trip yet. I would like to be around when they do, because that is the day a real design system stops being something only big teams can afford.

Sources and further reading:

About the author Christine Vallaure

I’m Christine Vallaure, a UI designer, speaker, founder of the learning platform moonlearning.io, and author of theSolo, a book about independent product building. I teach UI design, Figma, and product building with agentic AI to people who want to understand what is actually going on under the hood, through online courses, team training, and conference talks.

Sign up for the newsletter to stay in the loop.

Constitutionally incapable of writing a short article.


Design system contracts: the component lives in neither Figma nor code was originally published in UX Collective on Medium, where people are continuing the conversation by highlighting and responding to this story.

Need help?

Don't hesitate to reach out to us regarding a project, custom development, or any general inquiries.
We're here to assist you.

Get in touch