QuickstartLast updated on
Last updated on
Create your first form in minutes
Let's build a simple purchase agreement to grasp the basics of OpenForm. We'll define the agreement, populate it with data, validate it, and render the output.
Install the SDK
Let's make a new project and install the SDK.
mkdir quickstart && cd quickstart
npm init -y
npm install @open-form/sdk @open-form/resolversmkdir quickstart && cd quickstart
pnpm init -y
pnpm add @open-form/sdk @open-form/resolversmkdir quickstart && cd quickstart
yarn init -y
yarn add @open-form/sdk @open-form/resolversmkdir quickstart && cd quickstart
bun init -y
bun add @open-form/sdk @open-form/resolversDefine the Form
Let's define a simple purchase agreement with 2 parties and 3 fields. It will have a single layer that is a Markdown file.
import { open } from '@open-form/sdk'
const purchaseAgreement = open
.form()
.name('purchase-agreement') // required
.title('Purchase Agreement')
.version('1.0.0')
.parties({
buyer: open.party().label('Buyer').signature({ required: true }),
seller: open.party().label('Seller').signature({ required: true }),
})
.fields({
quantity: open.field.number().label('Quantity').required(),
price: open.field.money().label('Price').required(),
date: open.field.date().label('Date').required(),
})
.layers({
markdown: open.layer().file().mimeType('text/markdown').path('purchase-agreement.md'),
})
.defaultLayer('markdown')
.build()In this Quickstart, we're using the fluent builder pattern to define the form. You can also use the object pattern if you prefer.
Create the Layer
Next, let's create the layer. We'll use Handlebars syntax to map the form parties/fields to the layer template.
# Purchase Agreement
{{parties.buyer.fullName}} agrees to purchase {{quantity}} units at {{price}} each.
{{parties.seller.fullName}} agrees to deliver by {{date}}.OpenForm is agonstic to the rendering engine and file format you choose. You can use any rendering engine and file format you want.
Populate
Let's populate the form with data by using the .fill() method.
const draft = purchaseAgreement.fill({
fields: {
quantity: 100,
price: { amount: 25, currency: 'USD' },
date: '2025-03-01',
},
parties: {
buyer: { id: 'buyer-1', fullName: 'Alice Johnson' },
seller: { id: 'seller-1', fullName: 'Bob Smith' },
},
})Validate
Next, let's check that the data is valid by using the .isValid() method.
if (draft.isValid()) {
console.log('Purchase agreement is valid')
} else {
console.log('Errors:', draft.validate().errors)
}Render
Let's render the purchase agreement with the data using the .render() method.
import { textRenderer } from '@open-form/sdk'
import { createFsResolver } from '@open-form/resolvers'
const renderer = textRenderer()
const resolver = createFsResolver({ root: process.cwd() })
const output = await draft.render({ renderer, resolver, layer: 'markdown' })
console.log(output)
// Purchase Agreement
//
// Alice Johnson agrees to purchase 100 units at $25.00 each.
// Bob Smith agrees to deliver by March 1, 2025.Save Artifact
If we want to save our form for future use, we can either save it as a typescript file, or we can serialize it to JSON/YAML for future loading.
import { writeFileSync } from 'node:fs'
writeFileSync('purchase-agreement.json', purchaseAgreement.toJSON())import { writeFileSync } from 'node:fs'
writeFileSync('purchase-agreement.yaml', purchaseAgreement.toYAML()){
"$schema": "https://openform.sh/schemas/2026-01-01.json",
"kind": "form",
"name": "purchase-agreement",
"title": "Purchase Agreement",
"version": "1.0.0",
"fields": {
"quantity": { "type": "number", "label": "Quantity", "required": true },
"price": { "type": "money", "label": "Price", "required": true },
"date": { "type": "date", "label": "Date", "required": true }
},
"parties": {
"buyer": { "label": "Buyer", "signature": { "required": true } },
"seller": { "label": "Seller", "signature": { "required": true } }
},
"layers": {
"text": { "kind": "inline", "mimeType": "text/plain", "text": "..." }
},
"defaultLayer": "text"
}$schema: https://openform.sh/schemas/2026-01-01.json
kind: form
name: purchase-agreement
title: Purchase Agreement
version: 1.0.0
fields:
quantity:
type: number
label: Quantity
required: true
price:
type: money
label: Price
required: true
date:
type: date
label: Date
required: true
parties:
buyer:
label: Buyer
signature:
required: true
seller:
label: Seller
signature:
required: true
layers:
text:
kind: inline
mimeType: text/plain
text: "..."
defaultLayer: textThat's it! You've created a basic form that shows how OpenForm works at design time (defining the schema) and runtime (filling and rendering). As a next step, explore the concepts section or jump into the guides to learn more.