Fields
Fields define where signers need to sign, initial, or fill in information on a document.
Field Types
| Type | Description |
|---|---|
signature | Full signature (drawn or typed) |
initials | Initials only |
date | Auto-filled signing date |
text | Free-form text input |
checkbox | Boolean checkbox |
dropdown | Single choice from a fixed option list (options) |
Field Properties
| Property | Type | Description |
|---|---|---|
id | string | Unique identifier |
signerId | string | Which signer fills this field |
fieldType | enum | Type of field |
pageNumber | number | PDF page (1-indexed) |
xPosition | number | X coordinate from left edge (points) |
yPosition | number | Y coordinate from top edge (points) |
width | number | Field width (points) |
height | number | Field height (points) |
required | boolean | Whether field must be filled |
label | string | Prompt shown to the signer (e.g. “Your full name”) |
value | string | Filled value (null until signed) |
options | string[] | Allowed values for dropdown fields |
acroFieldName | string | Embedded PDF form field this field fills (see Fillable PDFs) |
maxLength | number | Maximum characters accepted at fill time |
validationPattern | string | Regex the value must match (see Fillable PDFs) |
validationMessage | string | Signer-facing error when the pattern does not match |
groupKey | string | Members sharing a key are mutually exclusive (choose-one) |
groupRequired | boolean | Require at least one member of the group to be selected |
requiredWhenFieldId | string | Conditional requirement: the field is required only while the referenced field is checked/filled (see Conditionally Required Fields) |
requiredWhenValue | string | Narrows the condition to one exact value of the referenced field |
sharedFill | boolean | Any signer able to act may fill or correct it until its owner signs (see Shared-Fill Fields) |
Adding Fields
TypeScript
// Add a signature field
const signatureField = await korala.fields.create(documentId, {
signerId: signer.id,
fieldType: 'signature',
pageNumber: 1,
xPosition: 100, // 100 points from left
yPosition: 500, // 500 points from top
width: 200,
height: 50,
});
// Add initials field
const initialsField = await korala.fields.create(documentId, {
signerId: signer.id,
fieldType: 'initials',
pageNumber: 1,
xPosition: 400,
yPosition: 700,
width: 80,
height: 40,
});
// Add date field (auto-fills when signed)
const dateField = await korala.fields.create(documentId, {
signerId: signer.id,
fieldType: 'date',
pageNumber: 1,
xPosition: 300,
yPosition: 500,
width: 150,
height: 30,
});Collecting Information from Signers
Signers can fill in fields themselves. The signer completes any field created
without a value in the signing UI, on the hosted signing page and inside
the embedded <KoralaSigner> iframe alike. Use this to collect
data your application doesn’t have, such as phone numbers or consent
checkboxes, without adding those questions to your own forms.
What the signer sees for each field type:
| Field Type | Signer interaction |
|---|---|
text | Inline text input on the document |
checkbox | Click to check |
date | Auto-fills the signing date on click |
signature | Opens the signature pad (draw or type) |
initials | Opens the signature pad for initials |
Date formats
When a signer clicks a date field, the filled value follows the format the
document requires, resolved in this order:
- The field’s
dateFormatproperty — e.g.dateFormat: 'MM-DD-YYYY'fills08-20-2026. Accepted formats combineD/DD,M/MM, andYY/YYYYtokens with a consistent-,/, or.separator; invalid formats are rejected at field creation. Only valid ondatefields — for typed text input, usevalidationPatterninstead. - A format token in the field’s
label— e.g.label: 'Date (MM-DD-YYYY)'. Handy when the label already prints the required format. - The field’s
validationPattern— common formats are tested against the regex and the first match is used (e.g.^\d{4}-\d{2}-\d{2}$fills2026-08-20). - Otherwise the signer’s browser-locale format.
Set dateFormat explicitly when the document mandates a format; template
fields carry it onto every generated document.
Set a label so the field shows a meaningful prompt instead of the generic
“Enter text”:
TypeScript
// The signer types their phone number into the document
await korala.fields.create(documentId, {
signerId: signer.id,
fieldType: 'text',
label: 'Phone number',
pageNumber: 1,
xPosition: 100,
yPosition: 400,
width: 200,
height: 30,
});
// The signer checks a consent box
await korala.fields.create(documentId, {
signerId: signer.id,
fieldType: 'checkbox',
label: 'I agree to the terms',
pageNumber: 1,
xPosition: 100,
yPosition: 450,
width: 30,
height: 30,
});Fields are required by default, so the signer cannot complete signing until they fill each required field. Korala stamps the filled values into the final PDF and returns them via the API once the signer has signed:
const fields = await korala.fields.list(documentId);
for (const field of fields) {
if (field.value) {
console.log(`${field.label ?? field.fieldType}: ${field.value}`);
}
}If you’re embedding the signing UI, the React SDK emits an
onFieldFilled event each time the signer fills a field, so your app can
track progress in real time.
Prefilled values are read-only by default. A text, date, dropdown, or
checkbox field that already has a value (for example from template merge variables,
bulk generation, or a signing-packet lock) renders in the signing UI as a
muted value with a “set by the sender” hint, and the signer cannot change it.
To prefill a value the signer may correct, set editable: true on the
template field; see Editable Defaults.
Prefill non-editable values only for data you’re certain of.
Each field reports who wrote its current value in filledBy: sender for a
non-editable prefill or a packet lock, signer for anything the signer
entered (including bulk signing on their behalf), and null while nobody has
filled it, which includes an editable default the signer has not confirmed.
The signing UI uses it to tell the sender’s values apart from the signer’s
own entries.
Shared-Fill Fields
Some forms are prepared by one party and confirmed by another: HR types the
employment details, the employee checks them and signs. Set
sharedFill: true on a field and any signer whose turn the signing order
allows may fill or correct it — until the field’s owner signs, which
freezes it for everyone.
await korala.fields.update(documentId, fieldId, {
sharedFill: true,
});The field still belongs to one signer. It counts toward their required fields, their signing locks the final value, and the completed PDF carries whatever stood when they signed — so the owner always has the last word on a prepared value. The audit trail records who actually wrote each value.
Rules to know:
sharedFillapplies totext,date,checkbox, anddropdownfields. Signature and initials fields refuse it: a signature can only come from its owner.- Order the owner after the preparer. A shared field owned by signer 1 freezes as soon as they sign, before signer 2’s turn ever starts.
- A required shared field is satisfied by a prepared value alone; keep the owner last in the signing order if they must see it before it counts.
In the signing UI, another signer’s shared field renders with a dashed border and names its owner. Template fields accept the same flag and carry it onto every generated document.
Conditionally Required Fields
Some fields are mandatory only when another answer makes them so. On the IRS W-9, the LLC tax-classification code (C, S, or P) must be filled only when the LLC classification box is checked. Express that by pointing the dependent field at its controller:
const llcBox = await korala.fields.create(documentId, {
signerId: signer.id,
fieldType: 'checkbox',
label: 'LLC',
pageNumber: 1,
xPosition: 73,
yPosition: 193,
width: 8,
height: 8,
required: false,
});
await korala.fields.create(documentId, {
signerId: signer.id,
fieldType: 'text',
label: 'LLC tax classification (C, S, or P)',
pageNumber: 1,
xPosition: 418,
yPosition: 192,
width: 29,
height: 11,
requiredWhenFieldId: llcBox.id,
});While the controller is off, the field stays optional. Once the signer
checks the box, the field turns required: it joins the progress counter,
gets required styling, and Korala refuses completion until it is filled,
with the error "LLC tax classification (C, S, or P)" is required when "LLC" is selected. Unchecking releases it again.
Rules to know:
- The controller must be a field on the same document belonging to the same signer. A checkbox controller counts when checked; any other type counts once filled.
- Set
requiredWhenValueto trigger only on one exact value — e.g. a dropdown’s"Other"choice requiring a “please specify” text field. - Korala stores a conditional field as individually optional, forcing its
requiredflag off at creation and rejectingrequired: trueon later updates while the condition stands. The condition alone decides. - Choose-one group members cannot carry a condition (the group’s
groupRequiredcovers them), though a group member — like the LLC box, part of the W-9’s classification group — can be a controller. - Clear a condition with
requiredWhenFieldId: nullon update. Clearing or re-pointing it also drops anyrequiredWhenValuenarrowing, since a value chosen for one controller means nothing against another. - Reassigning either field to a different signer clears the condition: the sign gate evaluates within one signer’s fields, so a cross-signer link could never be enforced and Korala refuses to store one that looks live.
- Template fields accept the same properties, and generated documents carry the condition with references remapped for you.
Coordinate System
PDF coordinates use points (1 point = 1/72 inch):
- Origin is at the top-left corner of the page
xPositionincreases going rightyPositionincreases going down- A standard US Letter page is 612 x 792 points
(0,0) ────────────────────────────► x (612)
│
│ ┌─────────────────┐
│ │ PDF Content │
│ │ │
│ │ ┌─────────┐ │
│ │ │ Field │ │
│ │ │(100,500)│ │
│ │ └─────────┘ │
│ │ │
│ └─────────────────┘
▼
y (792)Use the document viewer to find coordinates, or calculate positions from page dimensions.
Fillable PDFs (AcroForm)
Many pre-created documents, like the IRS W-9, ship as fillable PDFs with embedded form fields. Korala reads those fields and writes values back through them: detection proposes each field at its exact position, linked fields fill natively (SSN digits land one per comb box, checkboxes render the form’s own checkmark), and the completed document is flattened so it can no longer be edited.
See Fillable PDFs for the full flow,
including the GET /documents/{id}/form-fields discovery endpoint and
radio-group handling.
Recommended Field Sizes
| Field Type | Width | Height |
|---|---|---|
signature | 200 | 50 |
initials | 80 | 40 |
date | 150 | 30 |
text | 200 | 30 |
checkbox | 30 | 30 |
How Content Fills the Box
width and height set the field’s bounds. They do not set the size of
what lands inside it, so a box in the right place can still put the ink in the
wrong one.
Signatures and initials. Korala scales the image to fit inside the box, preserves its aspect ratio, then centres it on both axes — the same “contain” rule the signer preview uses, so a signature never stretches. Whichever dimension runs out first sets the scale, and the other gains padding.
Signature images are usually much wider than they are tall, so width is
normally the constraint. A 600 x 21 px signature in a 200 x 24 pt box scales
by 200 / 600, rendering about 7pt tall and leaving ~8pt of padding above and
below:
┌──────────────────────────────────┐ ← 24pt box
│ │
│ ~~~~~~~~~~~~~~~~~~~~~~~ │ ← ~7pt of ink, centred
│ │
└──────────────────────────────────┘To make the signature render larger, narrow the box rather than raising its height.
Text, date and dropdown. Values render left-aligned with 4pt of left
padding, centred against the box height, at min(12, height * 0.6) points
(a field imported from a fillable PDF keeps the point size, color and
alignment the form declares). A single-line value is never wrapped or shrunk
to fit, so a value wider than the box overflows it — size the box for your
longest expected value. A multiline field instead lays text out from the
top of the box, word-wrapped to its width, and drops lines that don’t fit
the height.
Checkbox. A checked box draws an X centred in the box, sized to
min(width, height) * 0.6. An unchecked field draws nothing. (A checkbox
linked to an embedded form field renders the form’s own checkmark instead —
see Fillable PDFs.)
The signing page previews filled values with these same rules — size, face, alignment and wrapping — so what a signer sees while filling is what the completed document shows.
Listing Fields
TypeScript
const fields = await korala.fields.list(documentId);
for (const field of fields) {
console.log(`${field.fieldType} on page ${field.pageNumber}`);
console.log(` Position: (${field.xPosition}, ${field.yPosition})`);
console.log(` Assigned to: ${field.signerId}`);
if (field.value) {
console.log(` Value: ${field.value}`);
}
}Removing Fields
TypeScript
await korala.fields.delete(documentId, fieldId);You can remove fields only while the document is in draft status.
Multiple Signers Example
Placing fields for multiple signers on the same document:
TypeScript
// Create document and add signers
const alice = await korala.signers.create(documentId, {
email: '[email protected]',
name: 'Alice (Seller)',
signingOrder: 1,
});
const bob = await korala.signers.create(documentId, {
email: '[email protected]',
name: 'Bob (Buyer)',
signingOrder: 2,
});
// Alice's fields (left side)
await korala.fields.create(documentId, {
signerId: alice.id,
fieldType: 'signature',
pageNumber: 2,
xPosition: 50,
yPosition: 650,
width: 200,
height: 50,
});
await korala.fields.create(documentId, {
signerId: alice.id,
fieldType: 'date',
pageNumber: 2,
xPosition: 50,
yPosition: 710,
width: 100,
height: 25,
});
// Bob's fields (right side)
await korala.fields.create(documentId, {
signerId: bob.id,
fieldType: 'signature',
pageNumber: 2,
xPosition: 350,
yPosition: 650,
width: 200,
height: 50,
});
await korala.fields.create(documentId, {
signerId: bob.id,
fieldType: 'date',
pageNumber: 2,
xPosition: 350,
yPosition: 710,
width: 100,
height: 25,
});Response Format
{
"id": "fld_abc123",
"documentId": "doc_xyz789",
"signerId": "sig_def456",
"fieldType": "signature",
"pageNumber": 1,
"xPosition": 100,
"yPosition": 500,
"width": 200,
"height": 50,
"required": true,
"value": null,
"signatureImageUrl": null,
"filledAt": null,
"filledBy": null,
"createdAt": "2024-01-14T09:00:00Z",
"updatedAt": "2024-01-14T09:00:00Z"
}