Design System Contracts

Spec reference

Conditionals, overlays & motion

Visibility, tightly-whitelisted literal styles, out-of-flow overlays, and declared motion — each with its cross-surface fidelity stated, never implied.

visibleWhen — conditional partsGeneratedCurated#

The part renders only when the prop matches. Boolean props map to canvas visibility bindings; enum conditions resolve per variant. Omit equals for booleans (truthy).

proprequiredstring

The driving prop, by canonical name.

equalsstring | string[]

Required for enum props; omit for booleans.

Refusals: 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).

  • an unknown prop; an equals value outside the enum
contracts/banner.contract.json (excerpt · v1.0.0) — shipping contract, loaded at build time
{
  "anatomy": {
    "root": {
      "parts": {
        "endArea": {
          "parts": {
            "close": {
              "description": "Close affordance — rendered only when isDismissable.",
              "element": "button",
              "visibleWhen": {
                "prop": "isDismissable"
              },
              "icon": {
                "asset": "close"
              },
              "attrs": {
                "aria-label": "Dismiss",
                "type": "button",
                "data-action": "dismiss"
              }
            }
          }
        }
      }
    }
  }
}

stylesWhen — conditional literal stylesGeneratedCurated#

Literal CSS — never tokens — applied when a prop matches. Boolean conditions ride the per-boolean data attribute the generator already emits (.root[data-is-disabled] { … }); enum conditions ride the root’s enum class. The whitelist is deliberately tight: behavioral and positional properties with no token vocabulary. A color or a dimension belongs in tokens, and a brace-wrapped value here is refused by name.

Whitelist (from STYLES_WHEN_ALLOWED in the schema): position, top, right, bottom, left, z-index, overflow, text-overflow, white-space, display, opacity, pointer-events, transform, transition, flex-direction, justify-content, align-items, cursor, text-decoration, mask.

proprequiredstring

Boolean or enum prop.

equalsstring

Required for enum props; must be omitted for booleans.

stylesrequiredRecord<string, string>

CSS property → literal value; keys must be in the whitelist.

Refusals: 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).

  • a property outside the whitelist
  • a value that looks like a token reference — token-driven styling belongs in tokens
  • equals missing on an enum condition, present on a boolean one, or outside the enum

Declared fidelity limit: v1 applies nothing on the canvas — boolean properties can bind visibility, not style. A code-side surface, like events.

contracts/text-field.contract.json (excerpt · v1.1.0) — shipping contract, loaded at build time
{
  "anatomy": {
    "root": {
      "stylesWhen": [
        {
          "prop": "isDisabled",
          "styles": {
            "opacity": "0.55",
            "pointer-events": "none",
            "cursor": "not-allowed"
          }
        }
      ]
    }
  }
}

overlay — out-of-flow attachmentGeneratedCurated#

The part renders out of flow, attached to one edge of the root — tooltip bubbles, combobox popups. Code: position: absolute with placement-derived insets, and the root becomes position: relative. Canvas: layoutPositioning: ABSOLUTE with placement-derived constraints, preserved through the amend path. Four placements in v1; offset and alignment tuning is a later axis.

placementrequired"top" | "bottom" | "start" | "end"

The root edge the part attaches to.

Refusals: 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).

  • the root cannot be an overlay — overlays attach to the root
  • an overlay cannot also grow (in-flow sizing) or overlap children (in-flow semantics)
an overlay bubble part — illustrative, schema-validated at build time
{
  "overlay": {
    "placement": "top"
  },
  "tokens": {
    "background-color": "{color.surface.raised}"
  }
}

No shipping contract carries overlay yet — the field-case tooltip (CBDS) pins its pointer with per-variant stylesWhen insets instead, which the shape page shows replayed from the committed capture. The example above is schema-validated at build time.

animation — declared motionGeneratedCurated#

CSS-side motion: spin for spinners, pulse for skeletons. Not representable on the canvas — a documented fidelity scope, like events. Nothing richer belongs in a contract: animation timing is behavior whose truth can’t be verified on both surfaces.

contracts/spinner.contract.json (excerpt · v1.0.0) — shipping contract, loaded at build time
{
  "anatomy": {
    "root": {
      "parts": {
        "arc": {
          "icon": {
            "asset": "spinner"
          },
          "animation": "spin"
        }
      }
    }
  }
}