Talking the same language
I heard it, you heard it. It's better when design and engineering share the same language. But what does that really mean? It's not designers learning to code, or developers learning design. It's sharing the same vocabulary and grammar. And this depends on the architecture decisions that will shape what you inherit, and what you author.
When you choose a framework you inherit language, its vocabulary and its grammar: the rules for how terms are formed, how components compose, how state flows, what's idiomatic and what fights the grain.
Naming conventions are the easiest place to see grammar at work. camelCase, kebab-case, PascalCase each carry meaning. A prop is onPress. A DOM attribute is on-press. A component is MyButton. A custom element is my-button. The casing tells you what kind of thing you're looking at. It's actual grammar, not decoration.
Composition is vocabulary too. Whether a thing is one component with a variant or two separate components. Whether children pass through a slot, a prop, or a render function. Whether a card "has" a header or "accepts" one. These are grammatical decisions about how parts relate, and they drift exactly like names do: one team nests, another flattens, both express the same intent, and the two halves of the system stop fitting together.
And above all of it sits the highest-stakes vocabulary of all, the categories themselves. What counts as a "variant" versus a "state" versus a "status." When one team files something under variant and another files the same thing under status, that's not a naming quibble. It's two different theories of what the component is, encoded in a single word, and it's the kind of drift that makes a system incoherent at the root.
So vocabulary is the nouns, the grammar, the composition rules, and the categories. The whole language. And a design system's defining question is where that language comes from.
This is also where the oldest pain in the field lives. The design handoff loses something in every interpretation, no matter how careful the spec, and the usual fixes, spec harder, sync more, never hold. The handoff wobbles because the two sides describe the same object in two different languages. Every fix that doesn't address the language just relocates the wobble.
Standardizing props is different
A prop is the thing the designer sets in Figma's panel and the thing the developer passes in code. Same slot, both hands. And designers know props perfectly well, they compose component APIs with them every day. The gap isn't knowledge, it's enforcement. A designer authoring a variant property in Figma has no way to know whether their variant is the same variant the code uses, because nothing resolves the two against a shared source of truth the way a plugin resolves token values. Both sides author the vocabulary independently, and independently authored vocabulary diverges.
That divergence is measurable. Scan a real library, compare every prop and value against a canonical vocabulary, and you can count it. In one system I audited, eighty-eight components across two platforms produced over two hundred distinct props and ten hard drift flags: a type here and a variant there meaning the same thing, a sizeVariant that was just size under another word. And the values drift worse than the props, because there are more of them and each component's author picks their own: outline, outlined, and bordered for one value; sm, small, and s for one size. Most of the flags were at the value level. The vocabulary frays at the values first.
The fix is the same move tokens made, one layer up: a shared look-up table both design and code compose against, defining which props exist and which values each accepts, one term per meaning at both levels, named by intent. Written down, resolved against on both surfaces, and therefore auditable. That last word is the whole point. A vocabulary you can audit is a contract.
But there's a reason props can't ride the same maturity path tokens did, and it's worth being honest about it. Tokens could standardize because values are framework-independent by nature: a color is a color in React, Vue, or SwiftUI, so a shared format could bind everyone without breaking anyone. Props can't, because prop vocabulary is downstream of the language and framework abstraction it lives in. It gets worse: a team's real vocabulary isn't even one framework's. It's a composite of the framework, the component libraries on top of it, and whatever sits between. There's no single binding point for a standard to attach to.
The two sides of the boundary are not equally hard, though. The code side is deterministic: because code is formal language, a prop map can be generated and queried by parsing the codebase directly, every prop and value extracted exactly as it exists. The source of truth builds itself from the code. The design side has no formal layer to parse against. Props would need a bespoke bridge per component library.
This is where an agent changes the structure of the problem, not just its convenience. Props need an interpreter, because there is no standard to converge on: the bridge has to be able to read your vocabulary, whatever composite of framework and library grammar it turned out to be. An agent connected to the prop map on the design system repo is that interpreter. A designer working through a component's intent and anatomy can ask which props and values the vocabulary accepts and have the prop table generated into the design tool on demand, not because someone built a plugin for that specific system, but because the contract was written in a form a machine can read and carry. This is the concrete payoff of the previous article's claim that contracts must be machine-readable: machines are how you easily enforce vocabulary across surfaces. And for props, where standardization is structurally unavailable, an adaptive machine is the only bridge that doesn't have to be rebuilt for every system.
Vocabulary should describe intention
Authored vocabulary can feel like free invention, but it isn't, because it still has to describe what an interface actually does. And what an interface does reduces to three things: input, how a user communicates intent to the system; feedback, how the system communicates state back; and structure, how the relationships between them get organized. The user or the world changes something, the state changes, and the system shows that change.
Variants are where this surfaces in the component vocabulary. A variant is the visual form of a state, and state is the feedback half of that loop. It's worth being precise: not every state comes from a user's action. A user action can change state, but so can the system on its own, a sync resolves, a permission expires, data arrives. The feedback is always about state; the user is only one of the things that can change it. A loading variant is feedback that something is processing, whether the user triggered it or a background sync did. A disabled variant is feedback that an action is unavailable, whether because of what the user did or a permission they never controlled.
This is why naming variants by intent isn't bookkeeping. Whether you inherit those names or author them, you're naming the feedback states of an interface, and the names have to describe the state, not the look. danger is feedback about consequence. success is feedback about outcome. Authored or inherited, the vocabulary bottoms out in the same HCI substrate, which is what keeps even a fully authored vocabulary anchored to something real instead of floating free as preference.