---
title: "Forms with JavaScript"
canonical_url: "https://www.nutrient.io/guides/android/samples/forms-with-javascript-kotlin/"
md_url: "https://www.nutrient.io/guides/android/samples/forms-with-javascript-kotlin.md"
last_updated: "2026-05-15T19:10:04.916Z"
description: "Create form fields with JavaScript actions for calculations and formatting."
---

# Forms with JavaScript

Create form fields with JavaScript actions for calculations and formatting.

[Get Started](https://www.nutrient.io/sdk/android/getting-started.md)

[All Samples](https://www.nutrient.io/guides/android/samples.md)

[Download](https://www.nutrient.io/guides/android/downloads.md)

[Launch Demo](https://www.nutrient.io/demo/)

---

```kotlin

/*
 *   Copyright © 2025-2026 PSPDFKit GmbH. All rights reserved.
 *
 *   The PSPDFKit Sample applications are licensed with a modified BSD license.
 *   Please see License for details. This notice may not be removed from this file.
 */

package com.pspdfkit.catalog.examples.kotlin

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.AssetManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.RectF
import android.net.Uri
import android.util.Log
import androidx.annotation.UiThread
import com.pspdfkit.annotations.actions.AnnotationTriggerEvent
import com.pspdfkit.annotations.actions.JavaScriptAction
import com.pspdfkit.catalog.R
import com.pspdfkit.catalog.SdkExample
import com.pspdfkit.configuration.activity.PdfActivityConfiguration
import com.pspdfkit.document.PdfDocument
import com.pspdfkit.document.processor.NewPage
import com.pspdfkit.document.processor.PdfProcessor
import com.pspdfkit.document.processor.PdfProcessorTask
import com.pspdfkit.forms.CheckBoxFormConfiguration
import com.pspdfkit.forms.PushButtonFormConfiguration
import com.pspdfkit.forms.TextFormConfiguration
import com.pspdfkit.ui.PdfActivity
import com.pspdfkit.ui.PdfActivityIntentBuilder
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import java.io.File
import java.io.IOException
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.forEach

/** This example showcases forms JavaScript functionality. */
class FormsJavaScriptExample(context: Context) :
    SdkExample(context, R.string.javaScriptFormsExampleTitle, R.string.javaScriptFormsExampleDescription) {
    @SuppressLint("SetJavaScriptEnabled", "CheckResult")
    override fun launchExample(context: Context, configuration: PdfActivityConfiguration.Builder) {
        configuration
            // JavaScript is enabled by default. It can be disabled in configuration..setJavaScriptEnabled(true)
            // Turn off saving, so we have the clean original document every time the example is launched..autosaveEnabled(false)

        // Create an empty document from scratch with multiple pages.
        val blankPage = NewPage.emptyPage(NewPage.PAGE_SIZE_A4).build()
        val task = PdfProcessorTask.empty()

        // Create multiple blank pages - we'll create example form fields on these pages.
        repeat(4) { index ->
            task.addNewPage(blankPage, index)
        }

        val outputFile =
            try {
                File(getCatalogCacheDirectory(context), "FormsJavaScriptExample.pdf").canonicalFile
            } catch (exception: IOException) {
                throw IllegalStateException("Couldn't create FormsJavaScriptExample.pdf file.", exception)
            }

        PdfProcessor.processDocumentAsync(task, outputFile).ignoreElements().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
                {
                    val intent =
                        PdfActivityIntentBuilder.fromUri(context, Uri.fromFile(outputFile)).configuration(configuration.build()).activityClass(FormsJavaScriptActivity::class.java).build()

                    context.startActivity(intent)
                },
                { throwable ->
                    Log.e(TAG, "Error while trying to create PDF document.", throwable)
                },
            )
    }

    companion object {
        private const val PSPDFKIT_DIRECTORY_NAME = "catalog-pspdfkit"

        @Throws(IOException::class)
        private fun getCatalogCacheDirectory(ctx: Context): File {
            val dir = File(ctx.cacheDir, PSPDFKIT_DIRECTORY_NAME)
            if (!dir.exists() &&!dir.mkdirs()) {
                throw IOException("Failed to create Catalog cache directory.")
            }
            return dir
        }
    }
}

/**
 * This activity shows how to create custom forms with JavaScript actions attached.
 *
 * Note: For more information about JavaScript API refer to our guides or Adobe's
 * JavaScript for Acrobat API Reference.
 */
class FormsJavaScriptActivity : PdfActivity() {
    @SuppressLint("CheckResult")
    @UiThread
    override fun onDocumentLoaded(document: PdfDocument) {
        super.onDocumentLoaded(document)

        document.formProvider.formElementsAsync.subscribe { formElements, _ ->
            if (!formElements.isNullOrEmpty()) return@subscribe
            createSimpleCalculationExample()
            createManualCalculationExample()
            createFormattingExample()
            createPushButtonWithImageImportAction()
            createCheckboxWithHideAction()
        }
    }

    private fun addTextField(
        name: String,
        pageIndex: Int,
        rect: RectF,
        text: String,
        actions: Map<AnnotationTriggerEvent, String> = emptyMap(),
        readOnly: Boolean = false,
    ) {
        document?.formProvider?.addFormElementToPage(
            name,
            TextFormConfiguration.Builder(pageIndex, rect).apply {
                    setText(text)
                    actions.forEach { (event, script) ->
                        setAdditionalAction(event, JavaScriptAction(script))
                    }
                    if (readOnly) setReadOnly(true)
                }.build(),
        )
    }

    private fun createSimpleCalculationExample() {
        addTextField(
            "sum-operand1",
            0,
            RectF(30f, 750f, 200f, 720f),
            "3.0",
            mapOf(
                AnnotationTriggerEvent.FORM_CHANGED to "AFNumber_Keystroke(2,0,0,0,'',true);",
                AnnotationTriggerEvent.FIELD_FORMAT to "AFNumber_Format(2,0,0,0,'',true);",
            ),
        )

        addTextField(
            "sum-operand2",
            0,
            RectF(30f, 690f, 200f, 660f),
            "4",
            mapOf(
                AnnotationTriggerEvent.FORM_CHANGED to "AFNumber_Keystroke(0,1,0,0,'',true);",
                AnnotationTriggerEvent.FIELD_FORMAT to "AFNumber_Format(0,1,0,0,'',true);",
            ),
        )

        addTextField(
            "sum-result",
            0,
            RectF(30f, 630f, 200f, 600f),
            "",
            mapOf(
                AnnotationTriggerEvent.FORM_CALCULATE to
                    "AFSimple_Calculate('SUM', new Array('sum-operand1','sum-operand2'));",
                AnnotationTriggerEvent.FIELD_FORMAT to "AFNumber_Format(2,1,0,0,'',true);",
            ),
            readOnly = true,
        )
    }

    private fun createManualCalculationExample() {
        addTextField("concat-operand1", 1, RectF(30f, 750f, 200f, 720f), "First")
        addTextField("concat-operand2", 1, RectF(30f, 690f, 200f, 660f), "Second")
        addTextField(
            "concat-result",
            1,
            RectF(30f, 630f, 200f, 600f),
            "",
            mapOf(
                AnnotationTriggerEvent.FORM_CALCULATE to
                    """
                    var operand1 = doc.getField('concat-operand1');
                    var operand2 = doc.getField('concat-operand2');
                    var result = doc.getField('concat-result');
                    result.value = operand1.value + ' ' + operand2.value;
                    """.trimIndent(),
            ),
            readOnly = true,
        )
    }

    private fun createFormattingExample() {
        addTextField(
            "Number format",
            2,
            RectF(30f, 750f, 200f, 720f),
            "3.2293",
            mapOf(
                AnnotationTriggerEvent.FORM_CHANGED to "AFNumber_Keystroke(2,0,0,0,'',true);",
                AnnotationTriggerEvent.FIELD_FORMAT to "AFNumber_Format(2,0,0,0,'',true);",
            ),
        )

        addTextField(
            "Currency format",
            2,
            RectF(30f, 690f, 200f, 660f),
            "33,99",
            mapOf(
                AnnotationTriggerEvent.FORM_CHANGED to "AFNumber_Keystroke(2,3,0,0,'€',true);",
                AnnotationTriggerEvent.FIELD_FORMAT to "AFNumber_Format(2,3,0,0,'€',true);",
            ),
        )

        addTextField(
            "Date format",
            2,
            RectF(30f, 630f, 200f, 600f),
            "02/07/2018",
            mapOf(
                AnnotationTriggerEvent.FORM_CHANGED to "AFDate_KeystrokeEx('mm/dd/yyyy');",
                AnnotationTriggerEvent.FIELD_FORMAT to "AFDate_FormatEx('mm/dd/yyyy');",
            ),
        )

        addTextField(
            "Time format",
            2,
            RectF(30f, 570f, 200f, 540f),
            "12:00:20",
            mapOf(
                AnnotationTriggerEvent.FORM_CHANGED to "AFTime_Keystroke('HH:MM::ss');",
                AnnotationTriggerEvent.FIELD_FORMAT to "AFTime_Format('HH:MM::ss');",
            ),
        )
    }

    private fun createPushButtonWithImageImportAction() {
        document?.formProvider?.addFormElementToPage(
            "pushbuttonfield",
            PushButtonFormConfiguration.Builder(
                    3,
                    RectF(30f, 750f, 120f, 660f),
                    getBitmapFromAsset(assets, "images/android.png"),
                ).setAction(JavaScriptAction("var f=this.getField('pushbuttonfield'); f.buttonImportIcon();")).build(),
        )
    }

    private fun createCheckboxWithHideAction() {
        document?.formProvider?.addFormElementToPage(
            "checkboxfield",
            CheckBoxFormConfiguration.Builder(3, RectF(150f, 690f, 180f, 660f)).deselect().setAdditionalAction(
                    AnnotationTriggerEvent.MOUSE_UP,
                    JavaScriptAction(
                        """
                        var pushButtonField = doc.getField('pushbuttonfield');
                        pushButtonField.display = (pushButtonField.display == display.hidden)? display.visible : display.hidden;
                        """.trimIndent(),
                    ),
                ).build(),
        )
    }

    private fun getBitmapFromAsset(assets: AssetManager, path: String): Bitmap = assets.open(path).use { BitmapFactory.decodeStream(it) }?: throw IllegalStateException("Failed to decode bitmap from assets: $path")
}

```

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.

---

## Related pages

- [Application Policy](/guides/android/samples/application-policy-kotlin.md)
- [Custom Form Highlight Color](/guides/android/samples/custom-form-highlight-color-java.md)
- [Custom Page Templates](/guides/android/samples/custom-page-templates-java.md)
- [Digital Signature (Basic)](/guides/android/samples/digital-signature-basic-kotlin.md)
- [Disabled Annotation Property](/guides/android/samples/disabled-annotation-property-java.md)
- [Image Document](/guides/android/samples/image-document-kotlin.md)
- [Compose Image Document](/guides/android/samples/compose-image-document-kotlin.md)
- [Inline Multimedia](/guides/android/samples/inline-multimedia-kotlin.md)
- [JavaScript Form Filling](/guides/android/samples/javascript-form-filling-kotlin.md)
- [Overlay Visibility](/guides/android/samples/overlay-visibility-kotlin.md)
- [PdfFragment](/guides/android/samples/pdffragment-kotlin.md)
- [Reader View](/guides/android/samples/reader-view-kotlin.md)
- [Playground](/guides/android/samples/playground-kotlin.md)
- [JavaScript Calculator](/guides/android/samples/javascript-calculator-kotlin.md)
- [Text Field Suggestions](/guides/android/samples/text-field-suggestions-kotlin.md)
- [Thumbnail Bar Modes](/guides/android/samples/thumbnail-bar-modes-kotlin.md)
- [Signature Storage Database](/guides/android/samples/signature-storage-database-kotlin.md)
- [Selection Customization](/guides/android/samples/selection-customization-java.md)
- [Password Protected PDF](/guides/android/samples/password-protected-pdf-kotlin.md)
- [Scientific Paper](/guides/android/samples/scientific-paper-kotlin.md)
- [Try Instant](/guides/android/samples/try-instant-kotlin.md)
- [Merge Documents](/guides/android/samples/merge-documents-kotlin.md)
- [Annotation Rendering](/guides/android/samples/annotation-rendering-kotlin.md)
- [Custom Data Provider](/guides/android/samples/custom-data-provider-kotlin.md)
- [Annotations with Transparency](/guides/android/samples/annotations-with-transparency-kotlin.md)
- [Annotation Flags](/guides/android/samples/annotation-flags-kotlin.md)
- [AI Assistant (Multiple Documents, ViewPager)](/guides/android/samples/ai-assistant-multiple-documents-viewpager-kotlin.md)
- [Custom Sharing Menu](/guides/android/samples/custom-sharing-menu-java.md)
- [Add LTV to Existing Signature](/guides/android/samples/add-ltv-to-existing-signature-kotlin.md)
- [Custom Toolbar Grouping](/guides/android/samples/custom-toolbar-grouping-java.md)
- [Custom Layout](/guides/android/samples/custom-layout-kotlin.md)
- [Custom ActionBar Actions](/guides/android/samples/custom-actionbar-actions-kotlin.md)
- [Custom Activity Toolbars](/guides/android/samples/custom-activity-toolbars-java.md)
- [Custom Note Hinter](/guides/android/samples/custom-note-hinter-kotlin.md)
- [Custom Main Toolbar](/guides/android/samples/custom-main-toolbar-kotlin.md)
- [Annotation Configuration](/guides/android/samples/annotation-configuration-kotlin.md)
- [Annotation Selection Styling](/guides/android/samples/annotation-selection-styling-kotlin.md)
- [Custom Search UI (Compose)](/guides/android/samples/custom-search-ui-compose-kotlin.md)
- [Document Switcher](/guides/android/samples/document-switcher-java.md)
- [File Annotation Creation](/guides/android/samples/file-annotation-creation-kotlin.md)
- [Dynamic Pages on Scroll](/guides/android/samples/dynamic-pages-on-scroll-kotlin.md)
- [Custom Activity Form Editing](/guides/android/samples/custom-activity-form-editing-java.md)
- [Custom Stamp Annotations](/guides/android/samples/custom-stamp-annotations-java.md)
- [Custom Outline Provider](/guides/android/samples/custom-outline-provider-kotlin.md)
- [Compose Navigation](/guides/android/samples/compose-navigation-kotlin.md)
- [Fragment Runtime Configuration](/guides/android/samples/fragment-runtime-configuration-kotlin.md)
- [Annotation Overlay](/guides/android/samples/annotation-overlay-java.md)
- [Instant Document JSON](/guides/android/samples/instant-document-json-kotlin.md)
- [DocumentView Composable](/guides/android/samples/documentview-composable-kotlin.md)
- [Form Creation](/guides/android/samples/form-creation-kotlin.md)
- [Document Download](/guides/android/samples/document-download-kotlin.md)
- [JavaScript Actions](/guides/android/samples/javascript-actions-kotlin.md)
- [Instant JSON Attachment](/guides/android/samples/instant-json-attachment-kotlin.md)
- [Digital Signature (Manual)](/guides/android/samples/digital-signature-manual-kotlin.md)
- [Digital Signature (Third-Party)](/guides/android/samples/digital-signature-third-party-kotlin.md)
- [Inline Search](/guides/android/samples/inline-search-java.md)
- [Form Filling](/guides/android/samples/form-filling-kotlin.md)
- [Form Click Intercept (Compose)](/guides/android/samples/form-click-intercept-compose-kotlin.md)
- [Document Sharing](/guides/android/samples/document-sharing-java.md)
- [Custom Download Dialog](/guides/android/samples/custom-download-dialog-java.md)
- [Download Progress](/guides/android/samples/download-progress-kotlin.md)
- [Popup Toolbar Customization](/guides/android/samples/popup-toolbar-customization-kotlin.md)
- [Custom Sharing Dialog](/guides/android/samples/custom-sharing-dialog-java.md)
- [PDF from Image](/guides/android/samples/pdf-from-image-kotlin.md)
- [Digital Signature (Two-Step)](/guides/android/samples/digital-signature-two-step-kotlin.md)
- [Remote URL](/guides/android/samples/remote-url-kotlin.md)
- [PdfUiFragment](/guides/android/samples/pdfuifragment-kotlin.md)
- [Runtime Configuration](/guides/android/samples/runtime-configuration-kotlin.md)
- [Sound Extraction](/guides/android/samples/sound-extraction-kotlin.md)
- [Document from Canvas](/guides/android/samples/document-from-canvas-kotlin.md)
- [Tabbed Documents](/guides/android/samples/tabbed-documents-kotlin.md)
- [Watermarks](/guides/android/samples/watermarks-kotlin.md)
- [Programmatic Zoom](/guides/android/samples/programmatic-zoom-kotlin.md)
- [Signature Parcelize](/guides/android/samples/signature-parcelize-kotlin.md)
- [OCR](/guides/android/samples/ocr-kotlin.md)
- [Vertical Scrollbar](/guides/android/samples/vertical-scrollbar-java.md)
- [Split View](/guides/android/samples/split-view-java.md)
- [XFDF Import/Export](/guides/android/samples/xfdf-import-export-kotlin.md)
- [UI View Modes](/guides/android/samples/ui-view-modes-kotlin.md)
- [LTV Signature](/guides/android/samples/ltv-signature-kotlin.md)
- [Bookmark Highlighting](/guides/android/samples/bookmark-highlighting-kotlin.md)
- [Custom Annotation Inspector](/guides/android/samples/custom-annotation-inspector-java.md)
- [Annotation Sidebar](/guides/android/samples/annotation-sidebar-kotlin.md)
- [AI Assistant (Single Document)](/guides/android/samples/ai-assistant-single-document-kotlin.md)
- [AI Assistant (Multiple Documents, Compose)](/guides/android/samples/ai-assistant-multiple-documents-compose-kotlin.md)
- [Document Comparison](/guides/android/samples/document-comparison-kotlin.md)
- [Document Processing](/guides/android/samples/document-processing-kotlin.md)
- [Custom Annotation Creation Toolbar](/guides/android/samples/custom-annotation-creation-toolbar-java.md)
- [Custom Electronic Signature](/guides/android/samples/custom-electronic-signature-java.md)
- [E-Learning](/guides/android/samples/e-learning-kotlin.md)
- [Electronic + Digital Signing](/guides/android/samples/electronic-digital-signing-kotlin.md)
- [Generate PDF Report](/guides/android/samples/generate-pdf-report-kotlin.md)
- [Multimedia Annotations](/guides/android/samples/multimedia-annotations-kotlin.md)
- [External Document](/guides/android/samples/external-document-kotlin.md)
- [Overlay Views](/guides/android/samples/overlay-views-kotlin.md)
- [Kiosk Grid](/guides/android/samples/kiosk-grid-kotlin.md)
- [Search Indexing](/guides/android/samples/search-indexing-kotlin.md)
- [Annotation Creation](/guides/android/samples/annotation-creation-kotlin.md)
- [Filterable Thumbnail Grid](/guides/android/samples/filterable-thumbnail-grid-kotlin.md)
- [Tabbed Documents (Persistent)](/guides/android/samples/tabbed-documents-persistent-kotlin.md)
- [Measurement Tools](/guides/android/samples/measurement-tools-kotlin.md)
- [HTML-to-PDF Conversion](/guides/android/samples/html-to-pdf-conversion-kotlin.md)
- [AES Encrypted File](/guides/android/samples/aes-encrypted-file-java.md)
- [Construction Floor Plan](/guides/android/samples/construction-floor-plan-kotlin.md)
- [Hide and Reveal Areas](/guides/android/samples/hide-and-reveal-areas-kotlin.md)
- [Multiple Documents (Compose Pager)](/guides/android/samples/multiple-documents-compose-pager-kotlin.md)
- [Screen Reader](/guides/android/samples/screen-reader-java.md)
- [Custom Search UI (Views)](/guides/android/samples/custom-search-ui-views-java.md)

