Spec reference
Props & bindings
The canonical API: names, five type kinds, defaults — and the bindings that render one prop onto two surfaces.
The canonical APICurated#
Each prop declares its canonical name, type, and default — and bindings, which describe how the one canonical prop manifests on each side. The canonical value set lives here and only here: canvas spelling ("Primary") and code spelling ("primary") are renderings of the canonical value.
Prop fieldsGeneratedCurated#
Canonical prop name — the spelling the contract owns.
Flows into JSDoc and Storybook autodocs.
See types.
Must match the type — enum defaults must be members, boolean defaults booleans, and so on (refused by name otherwise). Required text props must still declare a string default: it is the canvas default and the story sample.
Text props may be required (no default in the code signature).
See bindings.
TypesGeneratedCurated#
Five kinds, rendered from the schema union:
| Kind | Code surface | Canvas surface |
|---|---|---|
"boolean" | native attribute where the element supports it (disabled on <button>), otherwise a data-* attribute | BOOLEAN property |
"text" | children or a string prop | TEXT property |
"number" | number prop | TEXT property (stringified) |
{ enum: [...] } | typed union prop; one CSS class per value | VARIANT axis; every enum prop becomes an axis (full cartesian, defaults-first) |
{ arrayOf: {...} } | items?: Array<{ … }> — an optional array; undefined means “not provided”, never a silent [] | none — code-only by declared fidelity limit (see below) |
type: "boolean" | "text" | "number" | { enum: string[] } | { arrayOf: Record<string, "text" | "number" | "boolean"> }Declared fidelity limit — structured props. The canvas has no list-of-records property type, so an arrayOf prop must bind figma.kind: "NONE" and every design-side consumer skips it rather than reporting it behind. Both directions are enforced: arrayOf ⇔ kind "NONE".
{
"name": "items",
"type": {
"arrayOf": {
"iconRight": "boolean"
}
},
"bindings": {
"figma": {
"kind": "NONE"
},
"code": {
"prop": "items"
}
}
}Bindings — one prop, two manifestationsGeneratedCurated#
How the prop appears on the canvas: property kind, property name, and the canonical-value → variant-value spelling map.
The React prop name.
figma: { kind: "VARIANT" | "BOOLEAN" | "TEXT" | "INSTANCE_SWAP" | "NONE"; property?: string; values?: Record<string, string> }
code: { prop: string }Refusal rules on props and bindings: Each of these fails the build by name — the generator refuses, it never papers over (source: core/emit-react.ts validateContract, exercised by the C2 eval family).
- duplicate prop names; duplicate code bindings across props, slots, and events (the git-merge attack)
- two props binding the same design property — the canvas cannot host both
- an enum default outside the enum; type-mismatched defaults
- a figma
valuesmap missing an enum value, or carrying a key that is not one kind: "NONE"on a prop that is neitherarrayOfnortext— every other scalar prop has a canvas manifestation (atextprop may be code-only: a label the canvas carries as a raw per-instance character override, which has no component property to bind; it must declare a string default, since that default is what the canvas draws)bindings.figma.propertyrequired unless kind is"NONE"— and refused when it is
{
"props": [
{
"name": "variant",
"description": "Visual prominence of the action.",
"type": {
"enum": [
"primary",
"secondary",
"danger",
"ghost"
]
},
"default": "primary",
"bindings": {
"figma": {
"kind": "VARIANT",
"property": "Variant",
"values": {
"primary": "Primary",
"secondary": "Secondary",
"danger": "Danger",
"ghost": "Ghost"
}
},
"code": {
"prop": "variant"
}
}
}
]
}