Skip to content

feat: add an onClick option for a form field's mouse-up action - #1790

Open
KaiPressmar wants to merge 1 commit into
foliojs:masterfrom
KaiPressmar:acroform-aa-action-option
Open

feat: add an onClick option for a form field's mouse-up action#1790
KaiPressmar wants to merge 1 commit into
foliojs:masterfrom
KaiPressmar:acroform-aa-action-option

Conversation

@KaiPressmar

@KaiPressmar KaiPressmar commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

Feature. Fixes #1792.

A small, purpose-built option, along the lines invited in docs/forms.md's Advanced Form Field Use section ("If an option is not supported, open an issue on Github and it will be considered for addition to the API").

Context

There's no supported way to attach a mouse-up JavaScript action to a form field — most usefully, a push button that runs custom logic when clicked. The only path that ever reaches AA is mapFormat(), and only together with a format option, which is meant for keystroke/format validation, not arbitrary actions.

That's deliberate, not an oversight: pdfkit's docs explicitly say the handful of raw dictionary escape hatches still recognized (Ff, MK.CA, AA-with-format) are discouraged and may be removed. So rather than widening that raw access further, this adds a dedicated option instead.

The change

Adds an onClick option, accepted by all form annotation methods, mapped by a new mapActions(options, pdfObject) step (mirroring the other unconditional mappers) that sets the field's AA.U mouse-up action. mapFormat() still runs afterward and extends the same AA dictionary with format-validation actions when a format option is also given, so that combination keeps working.

onClick accepts either a plain string or a function. A function is stringified and invoked with this bound to the Document (exactly as Acrobat itself binds it in any field action) and Acrobat's own app, getField, display and event passed in as arguments — the same pattern tools like Puppeteer use for page.evaluate(fn). It still runs inside the PDF viewer's own JavaScript engine, not wherever the PDF was generated, so it can't close over outside variables.

doc.formPushButton('btn1', 10, 200, 100, 30, {
  label: 'Test Button',
  onClick: function (app) {
    app.alert('clicked');
    this.getField('otherField').value = 'updated from btn1';
  },
});

Passing the globals as parameters, rather than the more obvious route of declaring them as ambient TypeScript globals, is deliberate: a global event collides with the DOM lib's own deprecated window.event in any project with "dom" in its lib array, which I only found by actually trying it. Parameters sidestep that entirely — nothing is declared globally, so there's nothing to collide with.

A new types/acrobat-js.d.ts (exported via package.json's exports map) gives TypeScript projects real types for this signature, kept separate from pdfkit's own types so nothing is pulled in just by installing pdfkit:

import type { AcrobatOnClick } from 'pdfkit/types/acrobat-js';

const onClick: AcrobatOnClick = function (app) {
  app.alert('clicked');
};

This is deliberately a minimal, best-effort common subset (app, getField, display, event, the Document this), not a full Acrobat SDK type surface — documented as such, with contributions welcome to extend it.

Demo

Attached: a minimal PDF pair (a push button with an onClick action, before/after this change) plus screenshots from Adobe Acrobat/Reader. Before: clicking the button does nothing. After: it shows an alert.

image

Testing

  • yarn test:unit — all existing tests pass unchanged, plus new ones: a push button with a string onClick, one with a function onClick, and the combined onClick + format case.
  • yarn lint / yarn format — clean.
  • The new type declarations were verified against both classic (node) and node16 TypeScript module resolution, and against a project with "dom" in lib, using a throwaway project outside this repo (not part of the diff).

Checklist:

  • Unit Tests
  • Documentation
  • Update CHANGELOG.md
  • Ready to be merged

cc @blikblum for review.

@KaiPressmar KaiPressmar changed the title fix: recognize AA unconditionally, not only with a format option fix: form fields silently drop a custom AA (action) option Sep 5, 2026
@KaiPressmar
KaiPressmar force-pushed the acroform-aa-action-option branch 3 times, most recently from 105406c to dde6b58 Compare September 5, 2026 12:10
@KaiPressmar KaiPressmar changed the title fix: form fields silently drop a custom AA (action) option feat: add an onClick option for a form field's mouse-up action Sep 5, 2026
@KaiPressmar

Copy link
Copy Markdown
Contributor Author

Updated: on reflection this shouldn't widen the discouraged raw AA escape hatch further (the docs are explicit that even the existing ones are meant to shrink over time). Replaced with a purpose-built onClick option instead — description and diff updated above.

@KaiPressmar
KaiPressmar force-pushed the acroform-aa-action-option branch from dde6b58 to cea74ed Compare September 5, 2026 12:27
@KaiPressmar

Copy link
Copy Markdown
Contributor Author

Updated again: onClick now calls the function with app/getField/display/event as parameters (this bound to the Document) instead of relying on ambient TypeScript globals — a plain global event turned out to collide with the DOM lib's deprecated window.event. Added a small, opt-in types/acrobat-js.d.ts for TypeScript users on top of that. Description and diff updated above.

@KaiPressmar
KaiPressmar force-pushed the acroform-aa-action-option branch from cea74ed to 8732f59 Compare September 5, 2026 12:28
pdfkit deliberately restricted AcroForm options to documented mappings
and a small set of raw escape hatches (Ff, MK.CA, and AA only together
with a format option), with a stated intent to shrink and eventually
remove even those. A mouse-up JavaScript action on a field -- most
useful on a push button, e.g. to drive custom client-side logic -- had
no supported way to reach the API at all outside that discouraged,
format-only AA path.

Add a dedicated onClick option instead, consistent with the project's
stated direction of adding purpose-built options rather than widening
raw dictionary access: it needs no PDF dictionary knowledge, works on
its own, and still combines with format-validation actions exactly as
the old AA + format combination did.

Replaces the raw AA escape hatch: options.AA is no longer read at all,
only options.onClick.
@KaiPressmar
KaiPressmar force-pushed the acroform-aa-action-option branch from 8732f59 to 6e700f0 Compare September 5, 2026 12:33
@KaiPressmar

Copy link
Copy Markdown
Contributor Author

Note: the aa-before.pdf/aa-after.pdf attached above were built against an earlier version of this PR (the raw AA escape hatch, before the switch to the onClick option). They still demonstrate the same before/after behavior visually, but I'll swap in ones built against the current onClick-based code shortly.

@blikblum blikblum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides onClick, is there other event that can be set?

Comment thread docs/forms.md
doc.formPushButton('btn1', 10, 200, 100, 30, opts);
```

`onClick` also accepts a plain function, called with Acrobat's own `app`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify the description. Be objective hiding internal details, just with enough information to user create correct functions

Comment thread docs/forms.md
Comment on lines +151 to +154
onClick: function (app, getField) {
app.alert('clicked');
this.getField('otherField').value = 'updated from btn1';
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

param getField is not used. Is really necessary?

Comment thread docs/forms.md
Comment on lines +158 to +161
TypeScript projects can import `AcrobatOnClick` and the other types this
signature uses from `pdfkit/types/acrobat-js` — a small, best-effort set of
types for the handful of Acrobat globals most `onClick` handlers need, kept
separate from pdfkit's own types so nothing is declared globally:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nop. Types will be handled separately. Do not expose it for now. It can be documented internally

Comment thread docs/forms.md
### Advanced Form Field Use

Older implementations used to pass all unknown options to the internal PDF object structure. A small set of direct PDF dictionary escape hatches is still recognized: `Ff`, `MK.CA`, and `AA` when a `format` option is used but its use is discouraged and likely will be removed in future versions.
Older implementations used to pass all unknown options to the internal PDF object structure. A small set of direct PDF dictionary escape hatches is still recognized: `Ff` and `MK.CA`, but their use is discouraged and they may be removed in future versions. A previously-recognized `AA` escape hatch (only reachable together with a `format` option) has been replaced by the `onClick` option above, which needs no PDF dictionary knowledge and works on its own.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nop. This is not a changelog and no need to justify

Comment thread lib/mixins/acroform.js
// generated, so it can't close over outside variables, and only plain
// function syntax (not arrow functions or other syntax Acrobat's engine
// may not support) should be relied on.
const js =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep it simple, pass the base minimum arguments to get it working

Comment thread package.json
"require": "./js/output.cjs",
"default": "./js/output.mjs"
},
"./types/acrobat-js": {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support a mouse-up JavaScript action on form fields (onClick option)

2 participants