# FormsApi

Form filling, headless — the same rules as typing into the fields. `fields()` and `getValues()` read the form and need the `extract` feature; `setValues()` writes it and needs `forms` (without `forms`, a viewer shows fields read-only). Keys are fully qualified field names, as `fields()[].name` gives them (`topmostSubform[0].Page1[0].f1_01[0]`).

With a viewer open on the document, the values go through it — shown at once, on its undo stack, in `doc.save()` and in `viewer.createExporter()`'s output alike, and [`formFieldChanged`](https://kernstra.com/docs/web-sdk/api/events#ev-formfieldchanged) fires once per applied field. Without one they are written into the document itself, as a reader that typed them would: each field's value and its appearance, a formatted field shown formatted (`$1,234.50`) with its value as entered (`1234.5`), and calculated fields recalculated, so `doc.save()` and a viewer opened later both have them. A static XFA form, once filled, is saved as the AcroForm it is laid over.

Not available: resetting fields to their defaults, a flatten of the form alone (`doc.annotations.flatten()` and the export's `flatten` flatten everything), and FDF import. Field values travel as the `<fields>` of an XFDF file through [`exportXFDF`](https://kernstra.com/docs/web-sdk/api/doc-annotations/exportxfdf) / [`importXFDF`](https://kernstra.com/docs/web-sdk/api/doc-annotations/importxfdf). A field's `rect` is a [`Rect`](https://kernstra.com/docs/web-sdk/api/types#ty-rect) in page space.

- Kind: namespace
- Access: `doc.forms`

## Usage

```ts
const doc = await PDFDocument.fromUrl('/forms/w9.pdf');
const { rejected } = await doc.forms.setValues({
  'topmostSubform[0].Page1[0].f1_01[0]': 'Ada Lovelace',
  'topmostSubform[0].Page1[0].c1_1[0]': '1', // a check box, by its export value
});
if (rejected.length > 0) console.warn(rejected);
const filled = await doc.save();
```

## Reading

### `type`

```ts
type(): Promise<FormType>
```

The kind of form the document carries, as a `FormType`. Only AcroForm fields are interactive. Needs no feature.

- Kind: method
- Since: 1.0.0

Returns `Promise<FormType>`: `'none'`, `'acroform'`, `'xfa'` or `'xfa-foreground'`.

Throws:

- `DOCUMENT_CLOSED` — the document has been closed.

```ts
if ((await doc.forms.type()) === 'xfa') showNotice('Dynamic XFA forms are not interactive');
```

Page: https://kernstra.com/docs/web-sdk/api/doc-forms/type

### `fields`

```ts
fields(pageIndex?: number): Promise<FormFieldInfo[]>
```

The form's fields as the document holds them — every widget with its name, type, options, the booleans its flags set and the value the file carries (a check box's or radio button's export value when on, `'Off'` when off, as `getValues()` speaks it) — on one page, or on every page when the index is omitted. For what a viewer shows now, see `getValues()`. A document is read as at most 16 384 widgets: past that many, the rest of the form is left as the pages paint it, and `setValues()` reports those fields as `unknown_field`. Needs the `extract` feature.

- Kind: method
- Since: 1.0.0

| Parameter | Type | Description |
| --- | --- | --- |
| `pageIndex?` | `number` | Zero-based page index. Omit for every page. |

Returns `Promise<FormFieldInfo[]>`: Each with `name`, `type`, `value`, `pageIndex`, `rect`, `readOnly`, `required`, `noExport`, `multiline`, `password`, `comb`, `multiSelect`, `hidden` and, where set, `options`, `maxLength`, `exportValue`, `dateFormat`, `signature`, `format`, `range`, `calculation`, `look` and `rotation`.

Throws:

- `INVALID_ARGUMENT` — a page index out of range.
- `FEATURE_NOT_LICENSED` — the license lacks `extract`.
- `DOCUMENT_CLOSED` — the document has been closed.

```ts
const required = (await doc.forms.fields()).filter((f) => f.required && f.value === '');
```

Page: https://kernstra.com/docs/web-sdk/api/doc-forms/fields

### `getValues`

```ts
getValues(): Promise<Record<string, FormValue>>
```

Every field's value by fully qualified name: a text field's text, a check box's or radio group's export value when one is on and `'Off'` when none is, a choice field's option (a multi-select list box's choices as an array). Signature fields are left out. With a viewer open, what the viewer holds, typed values included. What it returns can be given back to `setValues()`; only read-only fields are refused. Needs the `extract` feature.

- Kind: method
- Since: 1.0.0

Returns `Promise<Record<string, FormValue>>`: By fully qualified name; a `FormValue` is a string, or an array of strings for a multi-select list box.

Throws:

- `FEATURE_NOT_LICENSED` — the license lacks `extract`.
- `DOCUMENT_CLOSED` — the document has been closed.

```ts
const values = await doc.forms.getValues();
await fetch('/submit', { method: 'POST', body: JSON.stringify(values) });
```

Page: https://kernstra.com/docs/web-sdk/api/doc-forms/getvalues

## Writing

### `setValues`

```ts
setValues(values: Record<string, FormValue | boolean>): Promise<SetFieldResult>
```

Sets fields by fully qualified name and resolves to a `SetFieldResult`; nothing is thrown for a field, a value of the wrong kind included. Every field is `read_only` when the document forbids filling it in — by its permissions, or by a certification that allows no changes. Needs the `forms` feature.

The rules, which a viewer open on the document applies through its fields: a text field keeps as many characters as its length limit allows; a formatted field (number, percentage, date, time, phone…) takes what its format accepts when typed, a date also as `YYYY-MM-DD`; a check box or radio group takes the export value of the widget to turn on, `'Off'` or `''` turning all off (a radio group that cannot be turned off refuses `'Off'`); a dropdown or list box takes one of its options — a multi-select list box its choices as an array (`[]` clears it; `''` clears any list box), and `''` is taken for a dropdown only when it holds no choice (a dropdown cannot be emptied); an array of more than one for a field that takes one is `invalid_value`; a comb field distributes characters as typing would, up to its length limit. Without a viewer a password field is refused (`unsupported_type`): a file never keeps a password field's text.

- Kind: method
- Since: 1.0.0

| Parameter | Type | Description |
| --- | --- | --- |
| `values` | `Record<string, FormValue \| boolean>` | By fully qualified name — a string, an array of strings for a multi-select list box, or a boolean: `true` turns a check box on (its export value), `false` turns a check box or radio group off (`'Off'`); `true` for a radio group is `invalid_value`, since a group has no one "on". |

Returns `Promise<SetFieldResult>`: `applied` names and `rejected` ones with a reason: `unknown_field`, `read_only`, `invalid_value` or `unsupported_type` (exported as `SetFieldRejection.UNKNOWN_FIELD`, `.READ_ONLY`, …).

Throws:

- `FEATURE_NOT_LICENSED` — the license lacks `forms`.
- `DOCUMENT_CLOSED` — the document has been closed.
- `EXPORT_FAILED` — with no viewer open, the document could not be saved to keep a formatted field's value as entered, or, on the form's first write, to name a font every reader has for its fields.
- `INVALID_STATE` — a progressive document still downloading.

```ts
const { applied, rejected } = await doc.forms.setValues({
  'topmostSubform[0].Page1[0].f1_01[0]': 'Ada Lovelace',
  'topmostSubform[0].Page1[0].c1_1[0]': true, // a check box, on
});
for (const { name, reason } of rejected) console.warn(name, reason);
```

Page: https://kernstra.com/docs/web-sdk/api/doc-forms/setvalues

Web page: https://kernstra.com/docs/web-sdk/api/doc-forms
