Design System Contracts

Spec reference

Events & toggles

Declared callbacks and mechanically generated toggles — the interaction surface both surfaces can verify, with everything richer left honestly to hand-written code.

The interaction surface, declaredCurated#

A contract declares what interactions exist without ever describing how they’re implemented. An event is a code-side callback (onToggle) fired when the trigger part is activated. The canvas cannot fire a callback, so events surface there as component-description text — a declared fidelity limit, like animation. (Distinguish this from state previews, where the canvas does now carry live behavior: hover and press are wired as prototype reactions. A reaction can move a variant; it cannot call your code.)

What events deliberately do NOT cover: drag, typeahead, focus trapping, animation timing — behavior whose truth can’t be verified on both surfaces. That stays a hand-written layer, and the contract refuses to pretend otherwise.

Event fieldsGeneratedCurated#

namerequiredstring

Event name, lowerCamel.

descriptionstring

Flows into JSDoc and the canvas component description.

bindingsrequired{ code: { prop: string } }

Code-only by declared fidelity limit: the callback prop, which must be on*.

triggerrequiredstring

The anatomy part (by name) whose activation fires the event; root allowed.

toggles{ prop: string; between: [string, string]; aria?: "expanded" | "checked" | "pressed" | "selected" }

See below.

Toggles — the generatable halfGeneratedCurated#

When toggles is present the generator emits the whole toggle mechanically: an uncontrolled useState fallback (interactive out of the box), the controlled/uncontrolled resolution, the flip between exactly two values of an enum prop, and the matching ARIA state attribute on the trigger. Values of the toggled enum outside the pair render aria-*="mixed" and resolve to the pair’s second value on activation — exactly Checkbox’s indeterminate.

proprequiredstring

The enum prop being flipped.

betweenrequired[string, string]

[offValue, onValue] — activation flips within the pair; any non-member value flips to onValue.

aria"expanded" | "checked" | "pressed" | "selected"

The ARIA state attribute generated onto the trigger.

Guardrails, enforced at build time: 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 trigger part must be an activatable element — keyboard activation comes from the platform, not a bolted-on handler
  • toggles.prop must be an enum containing both between values
  • event prop names must be on* and collision-free against props and slots
  • the differ treats the callback as contract API: deleting it from code is code BEHIND (eval: detect-code-removed-event)
contracts/switch.contract.json (excerpt · v2.0.0) — shipping contract, loaded at build time
{
  "events": [
    {
      "name": "toggle",
      "description": "Fires when the input is toggled; uncontrolled instances flip value off/on themselves.",
      "bindings": {
        "code": {
          "prop": "onToggle"
        }
      },
      "trigger": "input",
      "toggles": {
        "prop": "value",
        "between": [
          "off",
          "on"
        ],
        "aria": "checked"
      }
    }
  ],
  "props": [
    {
      "name": "value",
      "description": "On or off — drives the track color and thumb position.",
      "type": {
        "enum": [
          "off",
          "on"
        ]
      },
      "default": "off",
      "bindings": {
        "figma": {
          "kind": "VARIANT",
          "property": "Value",
          "values": {
            "off": "Off",
            "on": "On"
          }
        },
        "code": {
          "prop": "value"
        }
      }
    }
  ]
}