FormsLast updated on
Last updated on
Create, fill, and render a simple lease agreement
This guide walks through creating a lease agreement, filling it with data, and rendering the output.
Create a new project
Create a new project, set up the directory structure, and download the W-9 form:
mkdir my-form && cd my-form
npm init -ymkdir my-form && cd my-form
pnpm init -ymkdir my-form && cd my-form
yarn init -ymkdir my-form && cd my-form
bun init -yInstall the SDK
Install the SDK and the filesystem resolver.
npm install @open-form/sdkpnpm add @open-form/sdkyarn add @open-form/sdkbun add @open-form/sdkDefine the Form
A form needs a name, fields, and parties. Here's a simple lease agreement:
import { open } from '@open-form/sdk'
const lease = open.form({
name: 'lease-agreement',
version: '1.0.0',
title: 'Residential Lease Agreement',
parties: {
landlord: { label: 'Landlord', signature: { required: true } },
tenant: { label: 'Tenant', signature: { required: true } },
},
fields: {
address: { type: 'address', label: 'Property Address', required: true },
monthlyRent: { type: 'money', label: 'Monthly Rent', required: true },
startDate: { type: 'date', label: 'Start Date', required: true },
endDate: { type: 'date', label: 'End Date', required: true },
},
})Add a Layer
Templates define how forms render. Add an inline Markdown template using Handlebars syntax:
const lease = open.form({
name: 'lease-agreement',
// ...fields and parties
defaultLayer: 'markdown',
layers: {
markdown: {
kind: 'inline',
mimeType: 'text/markdown',
text: `
# Residential Lease Agreement
**Property:** {{address}}
**Monthly Rent:** {{monthlyRent}}
**Term:** {{startDate}} to {{endDate}}
**Landlord:** {{parties.landlord.fullName}}
**Tenant:** {{parties.tenant.fullName}}
`,
},
},
})Fill the Form
Use .fill() to create a runtime instance with data:
const filled = lease.fill({
parties: {
landlord: { id: 'landlord-1', fullName: 'Jane Smith' },
tenant: { id: 'tenant-1', fullName: 'John Doe' },
},
fields: {
address: {
line1: '123 Main St',
locality: 'Portland',
region: 'OR',
postalCode: '97201',
country: 'USA',
},
monthlyRent: { amount: 1500, currency: 'USD' },
startDate: '2025-02-01',
endDate: '2026-01-31',
},
})Party data requires an id field—this is used for signature tracking.
Render the Form
Render the filled form using the text renderer:
import { textRenderer } from '@open-form/renderer-text'
const output = await filled.render({
renderer: textRenderer(),
})
console.log(output)Output:
# Residential Lease Agreement
**Property:** 123 Main St, Portland, OR 97201, USA
**Monthly Rent:** $1,500.00
**Term:** February 1, 2025 to January 31, 2026
**Landlord:** Jane Smith
**Tenant:** John DoeFields are automatically serialized—money becomes $1,500.00, address becomes a formatted string.
Save the Artifact
Export the form to JSON or YAML for storage or version control:
const json = lease.toJSON() // or lease.toYAML()
console.log(JSON.stringify(json, null, 2)){
"$schema": "https://schemas.open-form.dev/schema.json",
"kind": "form",
"name": "lease-agreement",
"version": "1.0.0",
"title": "Residential Lease Agreement",
"fields": {
"address": { "type": "address", "label": "Property Address", "required": true },
"monthlyRent": { "type": "money", "label": "Monthly Rent", "required": true },
"startDate": { "type": "date", "label": "Start Date", "required": true },
"endDate": { "type": "date", "label": "End Date", "required": true }
},
"parties": {
"landlord": { "label": "Landlord", "signature": { "required": true } },
"tenant": { "label": "Tenant", "signature": { "required": true } }
}
}Load it back with open.load():
const loaded = open.load(jsonString) // works with JSON or YAML