← All help topics

TwinaForms Help

Using Custom JavaScript in TwinaForms.

Custom JavaScript lets you add browser-side automation to a published TwinaForms form. Use it for advanced field syncing, light custom behavior, and interaction patterns that go beyond the standard builder settings.

Where to add it

In TwinaForms Designer:

  1. Open the form.
  2. Open Form Settings.
  3. Open Advanced.
  4. Click Edit Custom JavaScript.
  5. Paste your code and save.
  6. Republish the form.
Important: Custom JavaScript runs in the browser, not in Salesforce or AWS. Use only trusted code.

Basic pattern

Most scripts use the same simple structure:

(function (TwinaForms) {
  function syncSomething() {
    const source = TwinaForms.getValue("text5") || "";
    TwinaForms.setValue("text6", source);
  }

  TwinaForms.on("change", function () {
    syncSomething();
  });

  syncSomething();
})(TwinaForms);

That gives you two important behaviors:

  • the script reacts when the user changes a field
  • the form also starts in the correct state on first load

Writing several functions

A form can have as many Custom JavaScript functions as you need. Two patterns work well — pick whichever fits the code you are writing.

Pattern A — one IIFE, multiple helpers

Use this when your functions share helpers or need to run together on the same event.

(function (TwinaForms) {
  function updatePhoneCode()  { /* ... */ }
  function updateFullName()   { /* ... */ }
  function updateSfDatetime() { /* ... */ }

  function syncAll() {
    updatePhoneCode();
    updateFullName();
    updateSfDatetime();
  }

  TwinaForms.on("change", syncAll);
  syncAll(); // initial state
})(TwinaForms);

Pattern B — separate IIFEs per concern

Use this when the concerns are unrelated. Each block is self-contained, so you can copy, paste, or remove one without breaking the others.

// Block 1: phone code sync
(function (TwinaForms) {
  function updatePhoneCode() { /* ... */ }
  TwinaForms.on("change", updatePhoneCode);
  updatePhoneCode();
})(TwinaForms);

// Block 2: GMT-to-SF datetime
(function (TwinaForms) {
  function updateSfDatetime() { /* ... */ }
  TwinaForms.on("change", updateSfDatetime);
  updateSfDatetime();
})(TwinaForms);
Trade-off: Pattern B is easier to manage when features come and go — delete a block, the rest keep working. Pattern A is tighter when helpers are shared (for example a common pad(), formatDate(), or getCountry()). If two IIFEs both listen to change, both run on every change — usually fine, but keep an eye on performance if one of them is expensive.

Examples

These examples use internal field IDs like text5, text6, and checkbox11. Use the actual field IDs from your form.

Build full name from two fields

Assume text1 is first name, text2 is last name, and text3 is full name.

(function (TwinaForms) {
  function updateFullName() {
    const first = (TwinaForms.getValue("text1") || "").trim();
    const last = (TwinaForms.getValue("text2") || "").trim();
    const fullName = [first, last].filter(Boolean).join(" ");
    TwinaForms.setValue("text3", fullName);
  }

  TwinaForms.on("change", function () {
    updateFullName();
  });

  updateFullName();
})(TwinaForms);

Set a greeting based on country

Assume text5 is country and text7 is greeting.

(function (TwinaForms) {
  function updateGreeting() {
    const country = TwinaForms.getValue("text5") || "";

    if (country === "Israel") {
      TwinaForms.setValue("text7", "Shalom");
      return;
    }

    if (country === "Spain") {
      TwinaForms.setValue("text7", "Hola");
      return;
    }

    TwinaForms.setValue("text7", "Hello");
  }

  TwinaForms.on("change", function () {
    updateGreeting();
  });

  updateGreeting();
})(TwinaForms);

Country to phone country code

Assume text5 is the country field and text6 is the phone code field.

(function (TwinaForms) {
  const phoneCodes = {
    "Israel": "+972",
    "United States": "+1",
    "Canada": "+1",
    "United Kingdom": "+44",
    "Germany": "+49",
    "France": "+33",
    "Spain": "+34",
    "Italy": "+39"
  };

  function updatePhoneCode() {
    const country = TwinaForms.getValue("text5") || "";
    TwinaForms.setValue("text6", phoneCodes[country] || "");
  }

  TwinaForms.on("change", function () {
    updatePhoneCode();
  });

  updatePhoneCode();
})(TwinaForms);

Show a section only when a checkbox is checked

Assume checkbox11 controls a section whose element id is sectionPromo.

(function (TwinaForms) {
  function syncSection() {
    const checked = TwinaForms.getValue("checkbox11") === true;
    if (checked) {
      TwinaForms.showElement("sectionPromo");
    } else {
      TwinaForms.hideElement("sectionPromo");
    }
  }

  TwinaForms.on("change", function () {
    syncSection();
  });

  syncSection();
})(TwinaForms);

GMT with Salesforce — write an SF Datetime value

Detects the submitter's current timezone (including Daylight Saving automatically), combines it with a Date field and a Time field, and writes an ISO 8601 string like 2026-04-23T14:30:00+03:00 into a hidden Text field. Map that hidden field to a Salesforce Datetime column on the Submit action. SF stores it in UTC and renders in each user's locale.

Assume date1 is the date the user picks, time1 is a TwinaForms Time field (HH:mm), and text5 is the hidden Text field submitted to SF.

(function (TwinaForms) {
  function pad(n) {
    return String(n || 0).padStart(2, "0");
  }

  function offsetPart() {
    var minutes = -new Date().getTimezoneOffset();
    var sign = minutes >= 0 ? "+" : "-";
    var m = Math.abs(minutes);
    return sign + pad(Math.floor(m / 60)) + ":" + pad(m % 60);
  }

  function datePart() {
    var val = TwinaForms.getValue("date1");
    if (val) return String(val);

    var d = new Date();
    return d.getFullYear() + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate());
  }

  function timePart() {
    var val = TwinaForms.getValue("time1");
    if (val) {
      var p = String(val).split(":");
      return pad(p[0]) + ":" + pad(p[1]) + ":" + pad(p[2]);
    }

    var d = new Date();
    return pad(d.getHours()) + ":" + pad(d.getMinutes()) + ":" + pad(d.getSeconds());
  }

  function updateSfDatetime() {
    var iso = datePart() + "T" + timePart() + offsetPart();
    TwinaForms.setValue("text5", iso);
  }

  TwinaForms.on("input", updateSfDatetime);
  TwinaForms.on("change", updateSfDatetime);

  updateSfDatetime();
})(TwinaForms);

Notes:

  • Half-hour timezones (India +05:30, Iran +03:30, Newfoundland -03:30) render correctly.
  • Privacy-hardened browsers (Tor, Firefox with privacy.resistFingerprinting) always report UTC. The script still produces valid ISO; it just records +00:00 for those users.
  • The Time field returns HH:mm. The script adds seconds as :00 when needed.
  • If the Time field is empty, the script uses the current browser time on page load or field change.
  • To store midnight instead of the current time when the Time field is empty, replace the last three lines of timePart() with return "00:00:00";.

Good practices

  • Keep scripts short and focused.
  • Prefer TwinaForms.getValue() and TwinaForms.setValue() over direct DOM selectors.
  • Republish after saving new code.
  • Test with realistic form values.

Avoid

  • very large scripts
  • code that depends heavily on the page HTML structure
  • untrusted copied code
Support note: TwinaForms officially supports the TwinaForms runtime API. TwinaForms does not automatically include third-party libraries such as jQuery, so prefer the built-in API and plain JavaScript unless you explicitly control that dependency. Direct DOM scripting may work, but it is less stable and may break more easily if the published HTML structure changes in future versions.