Intake 3 steps · 18 fields
Billing details, key contacts, brand assets and access, collected once when a client signs.
Get a hosted link and a responses inbox in a minute. No backend, no credit card.
Or set it up yourself
Live preview
{ "id": "client-onboarding", "title": "Welcome aboard", "submit": { "label": "Finish onboarding" }, "steps": [ { "id": "company", "title": "Company and billing", "fields": [ { "key": "legalName", "type": "text", "label": "Legal company name", "validation": { "required": true } }, { "key": "website", "type": "text", "label": "Website", "placeholder": "https://" }, { "key": "billingAddress", "type": "textarea", "label": "Billing address", "rows": 3, "validation": { "required": true } }, { "key": "taxId", "type": "text", "label": "Tax ID", "helperText": "EIN in the US, or your VAT or local tax number." }, { "key": "billingContact", "type": "text", "label": "Who handles invoices?", "placeholder": "Name and role" }, { "key": "billingEmail", "type": "email", "label": "Email for invoices", "inputMode": "email", "validation": { "required": true } }, { "key": "poRequired", "type": "radio", "label": "Do you need a purchase order number on invoices?", "layout": "inline", "options": [ { "value": "yes", "label": "Yes" }, { "value": "no", "label": "No" } ], "validation": { "required": true } }, { "key": "poNumber", "type": "text", "label": "PO number", "helperText": "Leave empty if you’ll send it later.", "show": [{ "field": "poRequired", "eq": "yes" }] } ] }, { "id": "people", "title": "Contacts", "fields": [ { "key": "contactName", "type": "text", "label": "Main contact", "validation": { "required": true } }, { "key": "contactEmail", "type": "email", "label": "Main contact email", "inputMode": "email", "validation": { "required": true } }, { "key": "contactPhone", "type": "phone", "label": "Main contact phone", "inputMode": "tel" }, { "key": "approver", "type": "text", "label": "Who signs off on work, if not the main contact?" }, { "key": "channel", "type": "radio", "label": "Where should we talk day to day?", "options": [ { "value": "email", "label": "Email" }, { "value": "slack", "label": "Slack" }, { "value": "teams", "label": "Microsoft Teams" }, { "value": "calls", "label": "Scheduled calls" } ], "validation": { "required": true } }, { "key": "timezone", "type": "text", "label": "Time zone", "placeholder": "City or UTC offset" } ] }, { "id": "assets", "title": "Assets and access", "fields": [ { "key": "assets", "type": "text", "label": "Link to brand assets", "placeholder": "https://", "helperText": "Logo, fonts and guidelines. A shared folder or Figma link works." }, { "key": "access", "type": "multiselect", "label": "What will we need access to?", "helperText": "We’ll send a secure way to share logins. Don’t paste passwords here.", "options": [ { "value": "cms", "label": "Website CMS" }, { "value": "dns", "label": "Domain and DNS" }, { "value": "hosting", "label": "Hosting" }, { "value": "analytics", "label": "Analytics" }, { "value": "social", "label": "Social accounts" }, { "value": "ads", "label": "Ad accounts" } ] }, { "key": "kickoff", "type": "date", "label": "Preferred kickoff date" }, { "key": "notes", "type": "textarea", "label": "Anything we should know before we start?", "rows": 3 } ] } ]}Copy the JSON into a file in your app, install the renderer and pass the definition to it. The same JSON works with @formhaus/vue.
npm i @formhaus/core @formhaus/reactimport { FormRenderer } from '@formhaus/react';
import '@formhaus/core/style.css';
import definition from './form.json';
export function Form() {
return (
<FormRenderer
definition={definition}
onSubmit={(values) => console.log(values)}
/>
);
}See Getting started for validation, steps and custom components.