Forms
A Hyphen form is how a person supplies structured data to a governed process. Two kinds exist and one renderer serves both:
- A form pause, the
PbotFormstep. A running case reaches a PbotForm step and waits for named keys. The pause is a task. Submitting resumes the run, once. Rendered with<hyphen-form run-id="ā¦" step-id="ā¦">. - An intake form, the external form. A standalone form with a schema and a trigger, created with
POST /external-forms. Submitting starts a workflow or a published process with the submission as input. Rendered with<hyphen-form form-id="ā¦">, the launcher, or the hosted page.
The full walkthrough of both is Forms, end to end.
Surfaces at a glance
| You want | Use | Needs |
|---|---|---|
| A link anyone can fill | https://<gateway>/forms/<formId> |
a public intake form |
| A form inside your own page | <hyphen-form form-id="ā¦"> |
the SDK script and your publishable key |
| A form in your page with no account or key for the visitor | <hyphen-form form-id="ā¦" public> |
the SDK script |
| A button that opens a form | <hyphen-form-button form-id="ā¦"> or data-hyphen-form="ā¦" on any element |
the SDK script |
| A form built from a sentence | POST /sdk/forms/generate |
the agent_forms feature on the organization |
| The forms a case is waiting on | <hyphen-task-sidebar>, or GET /sdk/forms/pending |
an SDK session |
| Fill a paused step from your own UI | <hyphen-form run-id="ā¦" step-id="ā¦"> |
a signed-in SDK session |
<hyphen-form>
Renders an intake form, a paused step, or an inline schema.
<!-- An intake form, under your session -->
<hyphen-form form-id="frm-ā¦" submit-text="Send" done-text="Received. We will be in touch."></hyphen-form>
<!-- The same form with no session: uses the public routes -->
<hyphen-form form-id="frm-ā¦" public public-base="https://<gateway>"></hyphen-form>
<!-- A paused step of a running case -->
<hyphen-form run-id="run-ā¦" step-id="2"></hyphen-form>
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
form-id |
string | An intake form to render | |
run-id + step-id |
string | A paused PbotForm step to render instead |
|
schema |
JSON | An inline form_schema_v1 document, for previews. Wins over the form's own schema |
|
public |
flag | off | Read and submit through the anonymous public routes; no session |
public-base |
URL | the SDK base | The gateway origin for public mode |
hide-title |
flag | off | Hide the form title |
submit-text |
string | Submit | Label on the submit button |
done-text |
string | Message shown after a successful submit |
Events
All events bubble and are composed, so they cross the shadow boundary.
| Event | Data | When |
|---|---|---|
hyphen-form:loaded |
{ schema, mode } |
The schema is resolved and rendered |
hyphen-form:page |
{ page, of } |
The person moves between pages |
hyphen-form:submitted |
{ payload, mode, response } |
The submit succeeded. For an intake form, response carries submission_id, triggered_run_id, and triggered_execution_type |
hyphen-form:error |
{ message } |
Load or submit failed |
How It Works
The fields come, in order of precedence, from a schema attribute, the schema authored on the form or the step, a schema generated once for that step when agent_forms is on, or a fallback of one text field per expected key. The submitted payload is always flat: { key: value }.
Submitting a paused step needs a signed-in session. An anonymous publishable-key session can read forms but not settle a pause; the gateway answers 403 with a hint. The engine records who submitted and refuses a second submit with 409.
<hyphen-form-button> and data-hyphen-form
A launcher opens a form in an overlay, or navigates to the hosted page.
<hyphen-form-button form-id="frm-ā¦" public>Start onboarding</hyphen-form-button>
<!-- Any element becomes a launcher -->
<a href="#" data-hyphen-form="frm-ā¦" data-hyphen-form-public>Dispute a charge</a>
<!-- Navigate to the hosted page instead of an overlay -->
<hyphen-form-button form-id="frm-ā¦" href target="_blank">Open the form</hyphen-form-button>
The launcher emits hyphen-form-button:opened and hyphen-form-button:closed on document.
Pages without a key
A static page that has no publishable key can still render public forms. Call HyphenSDK.defineFormElements() instead of HyphenSDK.init(); it registers only the form elements.
The hosted page
https://<gateway>/forms/<formId> renders a public intake form with no account and no key. The page is noindex, served with no-store, and reads the form through the gateway's anonymous proxy, which never exposes the organization id and rate-limits by IP: 60 reads and 10 submits per form per minute. The page follows the browser's theme; a Theme control in the header switches between auto, light, and dark and remembers the choice, and ?theme=dark or ?theme=light sets it for a link.
A successful submission answers 201 with submission_id, triggered_run_id, and triggered_execution_type (workflow_run or agent_run). The same facts arrive on the organization's webhooks as external_form_submitted.
If Hyphen saves the submitted payload but cannot start the configured run, the endpoint answers 502 form_trigger_failed. The response includes the durable submission_id and a trigger_failed status under error.details, so the accepted payload can be traced without treating the outcome as unknown. The webhook carries the same status.
Who is filling it in. With settings.requireAuth: true, the page asks for an email, sends a one-time code through the organization's existing email delivery, and submits with the resulting session. An unsigned submit on such a form is refused with 401 form_signin_required. The engine records submitted_by on the triggered run and on the webhook.
Branding. settings.branding white-labels the page: name and logoUrl replace the Hyphen wordmark, accent colors the controls, footer replaces the default line, and hidePoweredBy removes it.
Forms a running case is waiting on
When a case pauses on a PbotForm step:
- the pause is a task: it appears on the SDK event stream as
task:createdwithkind: "form", andGET /sdk/forms/pendinglists it; <hyphen-task-sidebar>lists it beside approvals with Fill it in and renders the form inline;- Process Studio shows Fill it in on the paused case;
<hyphen-form run-id="ā¦" step-id="ā¦">renders it anywhere.
Webhooks: form_pause_created, form_submitted, form_expired.
Styling
The components render in shadow DOM and read the --hyphen-* tokens from the host element: --hyphen-color-bg, --hyphen-color-text, --hyphen-color-border, --hyphen-color-primary, --hyphen-font-family, --hyphen-radius. Set them on hyphen-form in your stylesheet. See Theming.
Two audiences
A partner embedding Hyphen surfaces forms inside its own product under its publishable key, with <hyphen-form> or the launcher, and reads submissions through its session.
A Hyphen organization shares the hosted link with its clients, brands the page, and turns on sign-in when it needs to know who answered.
ā Next: Forms that start work Ā· Forms, end to end