Writing a Custom Primitive Prototype
Understand the minimal shape of direct and authored-asHook entries inside an approved boundary.
A leaf Prototype represents a protocol subject with a clear boundary and an independent information-flow responsibility. Button and Toggle are two relatively clear current examples.
This guide explains authoring structure; it does not approve a new Base identity. Before implementing a new Base subject, complete a maintainer checkpoint and follow the delivery workflow in Implementing an Approved Base Semantic Slice.
Start from entities and evidence
Section titled “Start from entities and evidence”Do not begin by copying source. For Button, read in this order:
- lifecycle, criteria, relations, and sources in
P-BASE-BUTTON; - cases and executable mappings in
T-BASE-BUTTON-0001; - packages/prototypes/base/src/button/button.proto.ts;
packages/prototypes/base/test/as-button.test.tsand applicable Adapter evidence; and- package exports, CLI, documentation, and demos.
P-BASE-BUTTON is currently draft. Source is implementation evidence, not authority above the applicable entity.
What base-button demonstrates
Section titled “What base-button demonstrates”Button has two official authoring entries:
- the
base-buttondirect Prototype; and - the
asButtonauthored asHook.
They share setupButton(def) instead of maintaining two versions of Button semantics. That arrangement realizes P-BASE-BUTTON-AUTHORING-ENTRIES; it is not a fixed template that every Prototype must copy.
The current implementation includes:
def.props.define()fordisabled;def.state.bool()for states such asdisabled,hovered, andpressed;asFocusable()forfocused,focusVisible, and the focus method;def.event.on()for pointer routes andpress.commit;def.expose.state(),def.expose.method(), anddef.expose.event()for outward surfaces; andasAccessible()for Button role, name, state, and action.
The former def.state.fromInteraction() example no longer describes the current Button implementation and must not be used as the example for this guide.
The boundary between def and run
Section titled “The boundary between def and run”def declares the setup-time plan: props, state, events, exposes, accessibility, rules, and lifecycle hooks. run appears inside runtime callbacks and provides access to current props, context, lifecycle, and outward effects.
For example:
def.event.on('press.commit', (run) => { if (disabled.get()) return; run.expose.emit('click');});The event route is registered during setup; the outward signal is emitted through run when the event occurs.
When to provide an authored asHook
Section titled “When to provide an authored asHook”Do not treat “exports a Prototype but no asHook” as a universal error. Ask:
- Does the applicable P catalog direct and authored-asHook forms as two entries of one protocol?
- Should both entries share the complete protocol surface and implementation?
- Does the hook serve only its owning protocol rather than becoming cross-Prototype substrate?
- Would the entry introduce ungoverned options, merge, or configure semantics?
D-PROTOTYPE-ENTITY-NAMING-0001 requires existing entries for one protocol to be cataloged in the same P entity; it does not require every direct Prototype to generate an asHook. D-AS-HOOK-CONFIGURABLE-AUTHORED-0001 also keeps ordinary configurable authored asHooks in governed future design space.
What completes a leaf slice
Section titled “What completes a leaf slice”A source file is only one part of delivery. An approved new leaf Prototype normally needs:
approved checkpoint→ P criteria and relations→ T cases and executable tests→ implementation and public exports→ CLI facade generation→ bilingual docs and real public-package demo→ applicable WC / React / Vue evidenceThe three current Adapter previews verify one Web host profile; they do not automatically prove multi-host conformance.
When to pause
Section titled “When to pause”If implementation needs a new public prop/event/state, changes ownership, requires a raw host object, or exposes a contradiction between P/T and implementation, return to the issue for a checkpoint instead of widening the boundary in source.
- For a compound family, read Writing a Compound Prototype
- For a design-language projection, read Building a Styled Library on Top of Base
- Before opening a pull request, use the Prototype Author Checklist