# Callbacks

Six places where the SDK hands you a decision or a job of its own — a dialog to replace, a link to open, a question to answer. **Callbacks decide; events observe.** Everything that merely happened — the page, the zoom, the tool, a field edited, entered or left, an error, a signature or stamp saved — is an event on `viewer.on(...)`, so any number of parts of your page can listen, and each can stop on its own: see [Events](https://kernstra.com/docs/web-sdk/api/events). The last four callbacks are how you replace or extend the SDK's own dialogs — see [What you can replace](https://kernstra.com/docs/web-sdk/guides/replace).

- Interface: `CallbacksConfig`
- Config path: `config.callbacks`

## Example

```ts
const viewer = new PDFViewer(container, doc, {
  callbacks: {
    onDownload: async () => {
      const presignedUrl = await fetchPresignedUrl(); // your API
      const exporter = viewer.createExporter();
      const res = await exporter.uploadTo(presignedUrl, { method: 'PUT' });
      if (!res.ok) showError(res.status); // uploadTo does not reject on an HTTP error
    },
    onExternalLink: (url) => {
      if (confirm('Open ' + url + '?')) window.open(url, '_blank', 'noopener,noreferrer');
    },
  },
});
```

## Options (6)

### `onDownload`

- Type: `() => void`
- Page: https://kernstra.com/docs/web-sdk/config/callbacks/ondownload

Takes over the toolbar Download button (after [`forms.validateRequired`](https://kernstra.com/docs/web-sdk/config/forms/validaterequired)). When set, the SDK's Download dialog and flow do not run; your function does — get the bytes from [`viewer.createExporter()`](https://kernstra.com/docs/web-sdk/api/pdfviewer/createexporter).

### `onPrint`

- Type: `() => void`
- Page: https://kernstra.com/docs/web-sdk/config/callbacks/onprint

Takes over the toolbar Print button and Ctrl / ⌘ + P; not called when the document forbids printing. When set, the SDK's Print dialog does not run; print with [`viewer.print({ pages })`](https://kernstra.com/docs/web-sdk/api/pdfviewer/print).

### `onSignatureRequest`

- Type: `(field: FormFieldInfo | null) => Promise<{ dataUrl: string } | null>`
- Page: https://kernstra.com/docs/web-sdk/config/callbacks/onsignaturerequest

Replaces the signature dialog, which then never opens. Called by the Sign tool (`field` is `null`) and by a form's signature field (`field` is that field); without the `extract` feature the field is blanked as `formFieldChanged`'s is. Must resolve with `{ dataUrl }` where `dataUrl` is a `data:` URL of a PNG, JPEG, WebP, GIF or BMP image, at most 10 MB. Anything else — `null`, a web address, SVG, a missing `dataUrl` — is a cancel, and so is a rejected promise (logged with `console.warn`). While a request is open, clicking the page or the same signature field again does not ask a second time. If the user switches tool before you answer, the answer is dropped.

### `onImageRequest`

- Type: `() => Promise<Blob | null>`
- Page: https://kernstra.com/docs/web-sdk/config/callbacks/onimagerequest

Replaces the Image tool's picker: called when the Image tool would open its file picker. Resolve with a `Blob` (a `File` is one) or `null` to cancel; the image is checked against [`tools.image`](https://kernstra.com/docs/web-sdk/config/tools/image) like a picked file and refused with the same message. A rejection is a cancel and is logged; the SDK shows nothing for a cancel, so tell the user yourself if your flow failed. An answer that arrives after the tool was switched off is dropped.

### `onExternalLink`

- Type: `(url: string) => void`
- Page: https://kernstra.com/docs/web-sdk/config/callbacks/onexternallink

Takes over web, `mailto:` and `tel:` links in the document. Receives only addresses that passed the SDK's scheme check: `http:`, `https:`, `mailto:` and `tel:` (an address written without a scheme arrives with `https://` in front). `javascript:`, `data:` and every other scheme never reach it, in-document links still jump to their page, and [`links.confirmExternal`](https://kernstra.com/docs/web-sdk/config/links/confirmexternal) no longer applies. The address is chosen by whoever wrote the document, so show it to the user before opening it, and open it with `noopener,noreferrer`. An exception thrown by your handler is logged with `console.error`.

### `onConfirm`

- Type: `(request: ConfirmRequest) => Promise<boolean> | boolean`
- Page: https://kernstra.com/docs/web-sdk/config/callbacks/onconfirm

Replaces the confirmation dialog ("Delete this page?"). Called in place of the SDK's confirmation dialog, for every question [`confirmations`](https://kernstra.com/docs/web-sdk/config/confirmations) has on, with the words the SDK would have shown (`title`, `message`, `confirmLabel`, `cancelLabel`) and what the action is about (`action`, `count`, `name`). `name` and `message` carry text from the document: show them as text, never HTML. Resolve `true` to go ahead; anything else, and a rejection (logged with `console.warn`), leaves things as they are.

```ts
new PDFViewer(container, doc, {
  callbacks: {
    onConfirm: async ({ action, title, message, confirmLabel, cancelLabel, count, name }) =>
      myDialogs.confirm({ title, body: message, ok: confirmLabel, cancel: cancelLabel, tone: 'danger' }),
  },
});
```

## Notes

**Callbacks decide; events observe.** A callback is where the SDK hands you a decision or a job of its own. Everything that merely happened is an event on [`viewer.on(...)`](https://kernstra.com/docs/web-sdk/api/pdfviewer/on); the field snapshot `formFieldChanged`, `formFieldFocused` and `formFieldBlurred` carry is described under [Events](https://kernstra.com/docs/web-sdk/api/events).

Ctrl / ⌘ + P goes to `onPrint` too. With the Print button hidden ([`toolbar.print: false`](https://kernstra.com/docs/web-sdk/config/toolbar/print)), the key is left to the browser.


Web page: https://kernstra.com/docs/web-sdk/config/callbacks
