Skip to content

Conventions

Declares how each library the pipeline touches is authored, and what it calls things. Every consumer reading the same libraries declares the same values — differing values produce incorrect output rather than merely different output: a mismatched pattern leaves a whole class of assets undetected, a mismatched state entry lands a concept on the wrong prop, and a mismatched primitive binding emits a component the design system does not have.

platforms

Conventions are keyed by platform. Figma is one key among the rest — this pipeline reads Figma to produce specs and writes specs to produce Figma, so it is a peer rather than a special case. Keys name implementations, not platform families: React and Web Components need different vocabularies and get different keys.

platforms:
figma:
naming: SENTENCE
glyphs:
match: 'DS Icon Glyph / {i}'
react:
stylesProp: sx
specs:
states:
disabled:
prop: isDisabled
primitives:
dsText:
elementType: text
map:
- source: content
prop: text

Absence of platforms means nothing is declared at all; absence of one key means that platform declares nothing.

Authoring

Each platform is authored as its own file in config/conventions/, named for the platform id. The file’s root is the entry — there is no platforms: wrapper to repeat:

config/
conventions/
figma.yaml
react.yaml
specs.yaml
settings.yaml
config/conventions/figma.yaml
naming: SENTENCE
glyphs:
match: 'DS Icon Glyph / {i}'

Because the filename is the platform id, two files cannot declare the same key and there is no merge rule. Absence of a member means that platform declares no such convention, and the capability it enables does not apply — there is no separate on-switch.

Two basenames in the directory are reserved and are not platforms: specs.yaml (conventions about the spec itself) and figma.primitives.yaml (the promotion table).

Platform members

A single shape serves every platform, with every member optional. Members fall into two groups:

  • Encoding — how this platform expresses something the spec models explicitly. A Figma library has no first-class notion of a subcomponent, so it encodes one in a layer-name pattern.
  • Vocabulary — which of this platform’s components implements a spec concept.

The shape is deliberately permissive: nothing stops a code platform declaring inferNumberProps. Discriminating by key would type figma differently from every other key, which is the special case the platform map removes.

PropertyTypeDefaultDescription
naming'NONE' | 'SENTENCE' | 'TITLE''NONE'Naming convention the Figma file uses — the reversal target for settings.spec.keys
glyphsobjectGlyph asset naming. Absent = no glyph convention
codeOnlyPropsobjectCode-only props container naming. Absent = no such convention
subcomponentsobjectSubcomponent organization and naming. Absent = no subcomponent convention
instanceExamplesobjectPro. Instance example organization and naming. Absent = no such convention
imagesobjectHow the library expresses images. Absent = no image convention
slotConstraintsbooleanfalseThe library authors slot constraints as code-only props
inferNumberPropsbooleanfalseThe library authors numeric props as Figma TEXT props with numeric defaults
stylesPropstringVocabulary. Prop receiving styling no promotion mapped. Absent = unmapped styling is dropped
defaultFillWidthnumberContainer width for a fill-width root. Absent = the rendering tool uses its own fallback

glyphs

PropertyTypeDefaultDescription
matchstring(required)Naming pattern identifying glyph assets. {i} = icon name (e.g. 'DS Icon Glyph / {i}')

codeOnlyProps

PropertyTypeDefaultDescription
matchstring(required)Literal layer name identifying the container (e.g. 'Code only props')

subcomponents

PropertyTypeDefaultDescription
scope'NESTED' | 'PAGE''NESTED'Where the library keeps subcomponents — the component’s own anatomy, or the whole Figma page
matchstring[](required)Naming patterns identifying subcomponents. {C} = component name, {S} = subcomponent name
excludestring[]Patterns the library excludes, same placeholders

instanceExamples

PropertyTypeDefaultDescription
scope'PAGE' | 'FILE''PAGE'Where the library keeps instance examples
matchstring[]Name filter. {C} = component name. Omitted = every in-scope instance qualifies
excludestring[]Patterns the library excludes, {C} placeholder
parentNamesstring[]A candidate’s immediate parent frame or section must match one of these

images

PropertyTypeDefaultDescription
backgroundImagebooleanfalseThe library expresses images as container fills, emitted as Styles.backgroundImage
matchstringVocabulary. Figma name of the designated image component (e.g. DS Image). Requires a non-empty sourceProps
componentstringVocabulary. The same component’s name on this platform (e.g. DsImage) — the translation target for a match declared by whichever platform produced the spec
sourcePropsstring[]Code-only prop names carrying image sources; the first is the designated component’s own source prop

stylesProp

Prop receiving styling no promotion mapped, for every promoted component on this platform (e.g. sx, style, modifier). A name only — what is placed in it is the generator’s decision.

defaultFillWidth

Width in pixels of the container this platform places a component in when the component’s root resizes to fill its parent.

Applies only when the root’s layoutSizingHorizontal is FILL. A root with a fixed or hugging width already states its width and is unaffected, so this can never override what a design declares — the number is the container’s width, not the instance’s.

config/conventions/figma.yaml
defaultFillWidth: 375

It has no default at any level. Absence means this platform declares no width and the rendering tool falls back to its own value.

specs

Conventions about the spec itself rather than about any platform. Authored at config/conventions/specs.yaml — a reserved basename beside the platform files. Every member names a prop (or an enum value) that exists in api.yaml, so a transform reading only the spec can apply it without touching the design tool: the CSS transform applies states and never opens a Figma file.

A sibling of platforms rather than a member of it: the spec is the hub every platform converts to or from, so making specs a platform key would name the hub as one of its own spokes.

These conventions are library-wide. The per-component equivalent is an annotation, which lands in the spec itself (anatomy.<element>.role); where both describe the same thing, the annotation wins.

config/conventions/specs.yaml
states:
disabled:
prop: isDisabled
hover:
prop: state
value: hover
accessibility:
label:
prop: a11yLabel
value:
prop: progress
indeterminate: isLoading

states

A map keyed by state concept name (e.g. hover, disabled, readonly). Each entry classifies one variant prop as that semantic state:

PropertyTypeDefaultDescription
propstring(required)Variant prop name (e.g. state, isDisabled)
valuestring"true"Variant value that activates this concept (e.g. "hover"). Omit for boolean props
contract'omit' | 'keep'(per concept)Contract generation override — exclude (omit, browser-driven) or retain (keep, consumer-controlled) the prop in generated Props interfaces

accessibility

Props carrying accessibility semantics no element expresses.

PropertyTypeDefaultDescription
label.propstringThe prop supplying an accessible name for a control with no text of its own — an icon-only button, typically. An element carrying a label part role wins over the prop

value

The props describing a control’s value where no element represents it — a progress bar draws its progress rather than writing it. An element carrying a value part role wins.

PropertyTypeDefaultDescription
propstring(required)The prop carrying the value
indeterminatestringA boolean prop forcing the indeterminate presentation regardless of the value

indeterminate sits here rather than among the state concepts because those are a governed vocabulary: each resolves to a canonical selector, and indeterminate there would mean a checkbox’s mixed state. A progress bar with no known value is a different fact wearing the same word — it suppresses aria-valuenow and has no selector at all.

primitives

Authored at config/conventions/figma.primitives.yaml — a reserved basename in the conventions directory, so no platform may take that id. The figma. qualifier is deliberate: the table’s source keys name Figma style properties and its values keys name Figma tokens, so the file describes the design tool even though the components it promotes to are not Figma-specific. Sits at the root of Conventions, beside platforms rather than inside a platform. A component’s props are the same whichever platform renders it, so the table is stated once.

Each key is one of the design system’s own component names. When promotePrimitives is on, a primitive layer in composed example content is promoted to an instance of the component whose entry best matches it.

PropertyTypeDefaultDescription
elementType'text' | 'glyph' | 'container'(required)The anatomy element type this component can be promoted from
maparray(required)Rules turning the layer’s styles into this component’s props, in precedence order

Several entries may share an elementType — a design system with a text, a heading and a body component is three entries. elementType names the same vocabulary anatomy uses, and describes the layer shape a promotion starts from, not the component it lands on: a component with its own internal anatomy is a legitimate target for a single drawn layer.

Rules

PropertyTypeDescription
sourcestringWhat is read from the captured layer
propstringThe prop this source’s value is written to, as-is
valuesobjectLiteral lookup from what the source carries to the props it writes

Exactly one of prop and values is given.

source is closed per element type, and honoured by implementations rather than enforced by the schema — so renaming a Styles member never invalidates a conventions file:

Element typeSources
texttypography, typography.fontSize, typography.fontFamily, typography.fontStyle, textColor, content
glyphwidth, height, fillColor, content
containerlayoutMode

The dotted sources address inside the Typography composite. typography is either a token reference or that composite, never both, so typography and the typography.* sources can never both resolve — declaring both is how one entry serves a layer wearing a text style and one styled ad hoc.

values

A key is a full token path or a raw scalar, matched literally. Nothing is derived from part of a token’s name, because a prop value need bear no relation to the token that produces it.

config/conventions/figma.primitives.yaml
dsHeading:
elementType: text
map:
- source: typography
values:
Typography theme/Headline/M: { appearance: Headline M }
Typography theme/Headline/XL: { appearance: Headline XL }
- source: content
prop: text
dsIcon:
elementType: glyph
map:
- source: fillColor
values: # colour in, intent out
Color/Critical: { appearance: error }
Color/Warning: { appearance: warning }
- source: width
values:
Constants/Sizing/4x: { size: XS }
- source: height # the same axis, reached by a raw value
values:
16: { size: XS }
- source: content
prop: name

A value writes one or more props, so one typography token can set size and weight together where another design system sets a single appearance.

Selection

When several entries share an elementType, the one whose rules resolve most often wins; ties break by declaration order. At least one rule must resolve, so elementType alone never promotes — a layer is only this component if something about it says so.

When more than one entry resolved, the promoted element records multipleMatches: true in its capture provenance — a durable note that the mapping was contested, rather than a warning that scrolls past.

A source with no matching row does not resolve. It stays in styles and reaches output as passed styling, so a component’s narrower prop enum constrains without a separate mechanism.

Resolution

ResolvedConventions applies defaults inside any declared platform entry: naming, slotConstraints and inferNumberProps are guaranteed once an entry exists, and within a declared block so are scope, backgroundImage, sourceProps, and each binding’s concept prop names. A platform’s stylesProp is folded into each declared primitive, so a consumer reads one level rather than two.

A resolver produces a complete entry for any platform it is asked about, declared or not — so a consumer reading figma gets naming: NONE whether or not a figma.yaml exists.

What no default can supply is a convention block: glyphs, subcomponents, images. Their absence is a statement about the library, and inventing one would fabricate a fact nobody declared. DEFAULT_CONVENTIONS is an empty object for the same reason a map has no fixed key to populate — not because the defaults went away.

In a spec’s metadata

metadata.conventions records the one platform entry that produced the spec, not every platform the workspace configures. The shape is identical, but absence means something different: here a missing platform did not produce this spec.

metadata:
conventions:
platforms:
figma:
naming: SENTENCE