Skip to main content

JavaScript PluginImproved in 5.17+

Freeform's JavaScript plugin handles AJAX submissions and client-side features such as conditional rules, date pickers, table fields, CAPTCHA, and Stripe payments. Additional scripts are loaded as needed for the fields and integrations used by each form.

Use the options and events below to customize or extend this behavior.

In Freeform 5.17+, the default AJAX renderer uses compatible formatting templates' banner and field-error styling. Custom JavaScript is optional for styling these elements.

Success and error messages can also be configured in the form builder. Use JavaScript overrides or rendering events when you need additional control. See AJAX Forms for examples.

​Getting Started

Use the freeform-ready event to override options during form initialization. Listen on document to apply changes to all forms, or on a specific form element to target only that form.

document.addEventListener('freeform-ready', (event) => {
event.options.showProcessingText = true;
event.options.processingText = 'Submitting...';
});

Replace myFormHandle with your form's handle and ensure my-form is unique on the page.

The freeform-ready event provides:

  • event.form — the form element.
  • event.freeform — the Freeform plugin instance.
  • event.options — an object for supplying option overrides.

See Plugin Options for the available settings.

​When to Call Your Custom Scripts

Register your event listeners before Freeform initializes the form. A listener added after initialization will not receive the earlier freeform-ready event.

Document-level listeners can be registered before the form markup exists. Listeners attached directly to a form require that element to exist first, so place them after the form markup.

Forms added dynamically to the page are automatically detected and initialized by the loaded Freeform plugin. Each newly initialized form also dispatches freeform-ready.

​Loading Freeform JS ManuallyImproved in 5.5+

To control where Freeform's assets appear in your template, set Script Insert Location to None under Form Behavior, then use the helpers below.

Manual loading controls where Freeform's assets are inserted. The loaded plugin still handles form initialization and its configured behavior, including AJAX submissions.

HelperWhat it loads
freeform.loadScripts([...])Assets selected by their script identifiers.
freeform.loadFreeformPlugin()The main Freeform JavaScript and CSS files.
freeform.loadFreeformPluginJs()Only the main JavaScript file.
freeform.loadFreeformPluginCss()Only the main CSS file.
freeform.loadFormSpecificScripts(form)Additional scripts and styles required by the specified form, such as CAPTCHA and JavaScript Test assets. Accepts a Freeform form object or form handle.

Load the main plugin once per page and include the additional assets needed by the forms on that page. These helpers generate the published asset URLs for you.

​loadScripts() ExampleRecommendedNew in 5.5.4+

Use loadScripts() when you want to explicitly select the assets to load:

{{ freeform.loadScripts([
'freeform',
'freeform.js-test',
'recaptcha.v3',
'stripe'
]) }}

Choose identifiers that match the features used by your forms. Common identifiers include:

  • freeform — the main Freeform JavaScript and CSS.
  • freeform.js-test — JavaScript Test.
  • recaptcha.v2-invisible
  • recaptcha.v2-checkbox
  • recaptcha.v3
  • hcaptcha.invisible
  • hcaptcha.checkbox
  • turnstileNew in 5.6.5+
  • stripe
  • field.calculationNew in 5.8.0+

Unlike loadFormSpecificScripts(form), this helper uses the identifiers you supply rather than inspecting a particular form.

​loadFreeformPlugin() and loadFormSpecificScripts() Example

Use this approach to load the main plugin together with the additional assets required by a particular form:

{% set form = freeform.form('myFormHandle') %}

{{ form.render() }}

{{ freeform.loadFreeformPlugin() }}
{{ freeform.loadFormSpecificScripts(form) }}

Replace myFormHandle with your form's handle. Place these calls after the form markup, typically near the end of the page.

​loadFreeformPluginCss(), loadFreeformPluginJs() and loadFormSpecificScripts() ExampleImproved in 5.14+

Use separate helpers to place the main stylesheet in the page head and JavaScript after the form markup:

{% set form = freeform.form('myFormHandle') %}

<html>
<head>
{{ freeform.loadFreeformPluginCss() }}
</head>
<body>
{{ form.render() }}

{{ freeform.loadFreeformPluginJs() }}
{{ freeform.loadFormSpecificScripts(form) }}
</body>
</html>

​Passing Custom Attributes to loadFreeformPlugin()

Pass attribute strings to customize the generated script and stylesheet tags. The first argument applies to the <script> tag; the second applies to the stylesheet <link> tag:

{{ freeform.loadFreeformPlugin(
'data-custom="script-value"',
'data-custom="stylesheet-value"'
) }}

You can also pass attributes to the separate helpers:

{{ freeform.loadFreeformPluginJs('data-custom="script-value"') }}
{{ freeform.loadFreeformPluginCss('data-custom="stylesheet-value"') }}

Register your freeform-ready listeners before the form initializes. See When to Call Your Custom Scripts.

​Form Events

Freeform dispatches events that let you customize form initialization, submission, and rendering.

Listen on document to handle events from all forms, or on a specific form element to target only that form. Each event includes:

  • event.form — the form element.
  • event.freeform — the Freeform plugin instance.

Additional properties are listed under each event below.

​Plugin Initialized: freeform-ready

Fires during initialization, before Freeform applies your option overrides and completes the form's setup.

Use event.options to supply overrides for the Plugin Options. Register your listener before the form initializes.

​Additional Property

  • options — an object for supplying option overrides.
document.addEventListener('freeform-ready', (event) => {
event.options.showProcessingText = true;
event.options.processingText = 'Submitting…';
});

Success and error messages can also be configured in the form builder. In Freeform 5.17+, compatible formatting templates provide styling for the default AJAX renderer, so JavaScript overrides are optional.

​On Submit: freeform-on-submit

Fires before Freeform submits the form, for both AJAX and regular submissions. Use it to modify field values, perform additional checks, or register asynchronous tasks.

Call event.preventDefault() to stop the submission.

​Additional Properties

  • isBackButtonPressed — whether the submission was triggered by the multi-page form's Back button.
  • addCallback(callback, priority = 0) — registers a callback that Freeform waits for before submitting.

The following example checks a checkbox field with the handle terms. Replace that handle and the validation logic to match your form.

const form = document.getElementById('my-form');

form.addEventListener('freeform-on-submit', (event) => {
if (event.isBackButtonPressed) return;

const terms = event.form.querySelector('input[name="terms"]');

if (terms && !terms.checked) {
event.preventDefault();
alert('Please accept the terms before submitting.');
}
});

​Asynchronous Submission Callbacks

Use event.addCallback() when a check or task must finish before the form submits. Freeform pauses submission while the registered callbacks run.

  • Return true or nothing to allow submission to continue.
  • Return false to stop submission.
  • Callbacks run sequentially, from lowest to highest priority.
  • The default priority is 0; negative priorities run before it.

This example calls a custom validation endpoint that returns an object such as { "valid": true }. Replace the endpoint and response handling with your own implementation.

const form = document.getElementById('my-form');

form.addEventListener('freeform-on-submit', (event) => {
if (event.isBackButtonPressed) return;

event.addCallback(async () => {
try {
const response = await fetch('/my-validation-endpoint');

if (!response.ok) {
throw new Error(`Validation request failed: ${response.status}`);
}

const result = await response.json();

if (!result.valid) {
alert('Please review your entries before submitting.');
return false;
}

return true;
} catch (error) {
console.error('Unable to validate the submission:', error);
alert('Unable to validate your entries. Please try again.');
return false;
}
}, -100);
});

Client-side checks supplement server-side validation. Validate any requirements that must be enforced on the server as well.

​On Reset: freeform-on-reset

Fires after Freeform resets the form following a completed, successful AJAX submission. Use it to reset custom interface elements or other client-side state.

This event is skipped when form resetting is disabled or Freeform redirects before resetting the form. It is a notification after the reset; preventing this event does not undo the reset.

document.addEventListener('freeform-on-reset', (event) => {
console.log('Form reset:', event.form);
});

To detect resets triggered outside Freeform's AJAX handling, listen for the form's native reset event instead.

​Handle Submission Actions: freeform-handle-actions

Fires when an AJAX response contains pending actions that require additional processing, such as payment actions.

This event concerns front-end submissions, not saving a form's configuration in the form builder. Freeform's integration scripts handle their supported actions automatically.

​Additional Properties

  • response — the parsed response object.
  • actions — the actions returned in the response.

This event is not cancelable.

document.addEventListener('freeform-handle-actions', (event) => {
console.log('Pending submission actions:', event.actions);
});

​Before Sending an AJAX Request: freeform-ajax-before-submit

Fires after Freeform prepares the submission data, but before it sends the AJAX request.

Use this event to modify the outgoing FormData. Call event.preventDefault() to stop the request from being sent.

​Additional Properties

  • data — the FormData containing the submission values.
  • request — the XMLHttpRequest object, before it has been opened or sent.
document.addEventListener('freeform-ajax-before-submit', (event) => {
event.data.set('myCustomValue', 'example');
});

The request has not been opened when this event fires, so you cannot call event.request.setRequestHeader() here.

​Before Processing an AJAX Response: freeform-before-ajax-success

Fires after Freeform receives an HTTP 200 AJAX response, before it processes the result.

Despite its name, this event also fires when the response contains validation errors or pending actions. Check the response properties before treating the submission as successful.

​Additional Properties

  • request — the XMLHttpRequest used for the submission.
  • response — the parsed response object.
document.addEventListener('freeform-before-ajax-success', (event) => {
const { success, finished } = event.response;

if (success && finished) {
console.log('A completed submission is ready to be processed.');
}
});

This event is cancelable. Calling event.preventDefault() stops Freeform's remaining response handling, including rendering feedback, replacing form HTML, processing pending actions, and updating the form payload.

Canceling this event does not undo the request or any submission already processed by the server. Use it when your code will take responsibility for handling the response.

For changes limited to success or error markup, use the rendering events documented below instead.

​After a Successful AJAX Submission: freeform-ajax-success

Fires when Freeform processes a successful AJAX response. For multi-page forms, this can mean advancing to the next page rather than completing the submission.

Check event.response.finished before running code intended for a completed submission.

​Additional Properties

  • request — the XMLHttpRequest used for the submission.
  • response — the parsed response object.
document.addEventListener('freeform-ajax-success', (event) => {
if (!event.response.finished) return;

console.log('Submission completed:', event.response.submissionId);
});

When the form's success behavior is a redirect, this event fires before Freeform redirects. Calling event.preventDefault() stops that automatic redirect.

For other success behaviors, Freeform processes the form HTML, reset, and success banner before dispatching this event. Preventing the event does not undo those actions.

​Custom Return URL

Configure redirects in the form builder whenever possible. To redirect a specific form using custom JavaScript, check that the submission is finished and a return URL is available:

const form = document.getElementById('my-form');

form.addEventListener('freeform-ajax-success', (event) => {
const { finished, returnUrl } = event.response;

if (finished && returnUrl) {
window.location.href = returnUrl;
}
});

See AJAX Forms for examples of configuring the return URL and overriding the form builder's success behavior.

Configure success messages in the form builder. Use plugin options for runtime overrides, or freeform-render-success when you need custom success markup or positioning.

​After an AJAX Error: freeform-ajax-error

Fires when an AJAX submission returns validation errors or encounters a request failure.

​Additional Properties

  • request — the request associated with the failure.
  • response — the parsed validation response, or error information for a request failure.
  • errors — field handles mapped to arrays of validation messages, when available.
  • formErrors — an array of form-level validation messages, when available.

Request failures may not include errors or formErrors, so check for them before accessing their contents.

document.addEventListener('freeform-ajax-error', (event) => {
console.log('Field errors:', event.errors || {});
console.log('Form errors:', event.formErrors || []);
console.log('Response:', event.response);
});

Calling event.preventDefault() on this event does not suppress Freeform's default validation feedback. Use freeform-render-field-errors or freeform-render-form-errors to customize rendering.

In Freeform 5.17+, compatible formatting templates provide styling for the default AJAX error renderer. JavaScript overrides remain available when additional customization is needed.

​After Processing an AJAX Response: freeform-ajax-after-submit

Fires after Freeform processes an HTTP 200 AJAX response and updates the form payload. It can follow a successful response, validation errors, or pending submission actions.

Use it for follow-up tasks that should run after normal response processing.

​Additional Properties

  • data — the submitted FormData.
  • request — the XMLHttpRequest used for the submission.
  • response — the parsed response object.

This event is not cancelable.

document.addEventListener('freeform-ajax-after-submit', (event) => {
console.log('AJAX response processed:', event.response);
});

This event does not fire for every submission attempt. Request failures, redirects, and canceled response processing can bypass it.

Use freeform-ajax-error to handle request failures, and freeform-ajax-success with a finished check to identify completed submissions.

​After a Failed or Canceled Submission: freeform-after-failed-submit

Fires when Freeform reports a stopped or unsuccessful submission, including:

  • A freeform-on-submit listener prevents submission.
  • A submission callback returns false.
  • An AJAX response contains validation errors.

Use it to restore custom interface state after these outcomes. It has no additional properties beyond form and freeform, and is not cancelable.

document.addEventListener('freeform-after-failed-submit', (event) => {
console.log('Submission stopped or validation failed:', event.form);
});

This event is not a notification for every possible request failure. Use freeform-ajax-error when you need the validation or request-error details.

​Rendering Success Messages: freeform-render-success

Fires before Freeform renders an AJAX success banner.

This event is optional. Configure messages in the form builder and use formatting-template styling for the default renderer. Use this event when you need custom markup or positioning.

Call event.preventDefault() to replace the built-in renderer.

The following example places the success banner at the bottom of the form while using its configured message and classes:

document.addEventListener('freeform-render-success', (event) => {
event.preventDefault();

const { options } = event.freeform;
const banner = document.createElement('div');
const message = document.createElement('p');

banner.className = options.successClassBanner || '';
banner.setAttribute('role', 'status');
banner.setAttribute('data-freeform-ajax-banner', 'success');

message.textContent = options.successBannerMessage || '';
banner.appendChild(message);

event.form.appendChild(banner);
});

The data-freeform-ajax-banner attribute allows Freeform to remove the custom banner during normal AJAX cleanup.

If your formatting template already provides a custom success-rendering handler, modify that handler rather than adding another one.

​Rendering Form Errors: freeform-render-form-errors

Fires before Freeform renders the AJAX error banner.

In Freeform 5.17+, compatible formatting templates provide styling for the default banner. Use this event when you need custom markup or positioning, and call event.preventDefault() to replace the built-in renderer.

​Additional Property

  • errors — an array of form-level error messages. It may be empty when validation errors belong only to individual fields.

The following example places the error banner at the bottom of the form. It displays the configured error message followed by any form-level errors:

document.addEventListener('freeform-render-form-errors', (event) => {
event.preventDefault();

const { options } = event.freeform;
const banner = document.createElement('div');
const message = document.createElement('p');

banner.className = options.errorClassBanner || '';
banner.setAttribute('role', 'alert');
banner.setAttribute('data-freeform-ajax-banner', 'error');

message.textContent = options.errorBannerMessage || '';
banner.appendChild(message);

const errors = event.errors || [];

if (errors.length) {
const list = document.createElement('ul');

errors.forEach((error) => {
const item = document.createElement('li');
item.textContent = error;
list.appendChild(item);
});

banner.appendChild(list);
}

event.form.appendChild(banner);
});

This replaces only the form-level banner. Field errors continue to use their existing rendering behavior.

If your formatting template already provides a custom form-error renderer, modify that handler instead of adding another one.

​Rendering Field Errors: freeform-render-field-errors

Fires before Freeform renders individual field validation errors.

In Freeform 5.17+, the default renderer uses compatible formatting templates' field-error styling and supported error-state classes. It also handles accessibility attributes that connect errors to their inputs.

Listen to this event to inspect errors or perform additional tasks. Call event.preventDefault() only when you intend to replace the built-in field-error renderer.

​Additional Property

  • errors — an object mapping field handles to arrays of validation messages.

The following example logs field errors while allowing Freeform to display them normally:

document.addEventListener('freeform-render-field-errors', (event) => {
Object.entries(event.errors || {}).forEach(([handle, messages]) => {
console.log(`Validation errors for ${handle}:`, messages);
});
});

If you replace field-error rendering, your implementation must handle the error markup, field styling, accessibility relationships, and cleanup.

For class changes alone, use formatting-template overrides or the relevant Plugin Options.

​Removing Success and Error Banner Messages: freeform-remove-messages

Fires before Freeform clears existing AJAX messages and error styling, including when it processes a subsequent submission response.

Freeform handles cleanup for its default renderer. Custom banners also participate in this cleanup when they use the appropriate marker:

  • data-freeform-ajax-banner="success"
  • data-freeform-ajax-banner="error"

You do not need a separate cleanup handler solely because you changed banner classes or used these markers.

Use this event to remove additional elements created by your custom rendering code. The following example removes elements marked with data-custom-form-message while allowing Freeform's normal cleanup to continue:

document.addEventListener('freeform-remove-messages', (event) => {
event.form
.querySelectorAll('[data-custom-form-message]')
.forEach((element) => element.remove());
});

This event is cancelable. Call event.preventDefault() only when your implementation will replace all of Freeform's default message and error-state cleanup.

​Removing Field Messages: freeform-remove-field-messages

Fires before Freeform clears validation feedback for a field, including when its value changes.

The default cleanup removes the field's error messages, restores its styling, and clears the accessibility attributes associated with its validation errors.

​Additional Property

  • field — the input, select, or textarea element whose feedback is being cleared.

Use this event to clean up additional field-level elements or classes created by your custom code. This example removes a custom class and message blocks marked with data-custom-field-errors:

document.addEventListener('freeform-remove-field-messages', (event) => {
const field = event.field;
const container = field.closest('[data-field-container]');

field.classList.remove('my-custom-error-class');

container
?.querySelectorAll('[data-custom-field-errors]')
.forEach((element) => element.remove());
});

This example supplements Freeform's cleanup without preventing it.

Call event.preventDefault() only when replacing the default field cleanup. Your implementation must then remove the relevant error markup, restore field styling, and update accessibility attributes while preserving links to instructions or other descriptions.

​Plugin Options

Use plugin options to override settings during the freeform-ready event. Most forms can use their form-builder settings and formatting-template styles without additional JavaScript.

Listen on document to apply overrides to all forms, or on a specific form element to target only that form.

document.addEventListener('freeform-ready', (event) => {
event.options.successBannerMessage = 'Thank you! Your form was submitted.';
event.options.errorBannerMessage = 'Please review your entries and try again.';
});

Success and error messages can also be configured and translated in the form builder. JavaScript message overrides take precedence over those configured messages.

​Submission and Validation

OptionTypeDescription
ajaxbooleanEnables or disables built-in AJAX submission handling. Normally controlled by Use AJAX in the form builder.
disableSubmitbooleanDisables submit buttons while Freeform processes a submission, then enables them again when processing ends.
disableResetbooleanPrevents Freeform from resetting field values after a completed, successful AJAX submission.
skipHtmlReloadbooleanPrevents Freeform from replacing the form's contents with HTML returned by an AJAX response.
focusFirstErrorbooleanMoves focus to the first visible field with a validation error, or to the error banner when no field can be focused.
autoScrollbooleanScrolls to the form after an AJAX response is processed. Successful error focusing takes precedence over this scrolling.
scrollToAnchorbooleanScrolls to the form during initialization when enabled.
scrollOffsetnumberAdjusts the scrolling position in pixels. Defaults to 0; a negative value can leave space above the form for a fixed header.
scrollElementWindow or HTMLElementThe target used for scrolling. Defaults to window.

disableReset and skipHtmlReload control different operations. Disabling the reset does not prevent HTML replacement, and skipping HTML replacement does not prevent field resetting.

For custom markup and multi-page considerations, see AJAX Forms.

​Processing Feedback

OptionTypeDescription
showProcessingSpinnerbooleanEnables the submit button's processing indicator.
showProcessingTextbooleanReplaces the submit button's text while the submission is processing.
showProcessingOverlaybooleanDisplays a processing overlay over the form.
processingTextstringThe text used for the processing button text and overlay.
document.addEventListener('freeform-ready', (event) => {
event.options.showProcessingText = true;
event.options.showProcessingOverlay = true;
event.options.processingText = 'Submitting…';
});

​Success and Error Messages

OptionTypeDescription
successBannerMessagestringThe message displayed by the default AJAX success-banner renderer.
errorBannerMessagestringThe summary message displayed by the default AJAX error-banner renderer.

These options change the banner messages. They do not replace individual field-validation messages or additional form-level errors.

​Success and Error StylingImproved in 5.17+

In Freeform 5.17+, the default AJAX renderer uses compatible formatting templates' banner attributes, field-error styling, and supported error-state classes.

JavaScript class overrides remain available. Existing overrides can stay in place; updating to 5.17 does not, by itself, require removing or replacing them.

OptionTypeBehavior in 5.17+
successClassBannerstringOverrides the success-banner classes inherited from the formatting template. Without template classes or an override, the fallback is freeform-form-success.
errorClassBannerstringOverrides the error-banner classes inherited from the formatting template. Without template classes or an override, the fallback is freeform-form-errors.
errorClassListstringA value other than freeform-errors overrides the field-error block's inherited classes. Leaving this at freeform-errors allows template classes to be inherited when a matching rendered error block is available.
errorClassFieldstringAdds classes to invalid inputs alongside the formatting template's error-state classes. Defaults to freeform-has-errors; it does not replace template classes.

Class options accept multiple class names separated by spaces:

document.addEventListener('freeform-ready', (event) => {
event.options.successClassBanner = 'alert alert-success';
event.options.errorClassBanner = 'alert alert-danger';
event.options.errorClassList = 'my-field-errors';
event.options.errorClassField = 'my-invalid-input';
});

Custom rendering handlers control their own output. If a formatting template or your JavaScript replaces the default renderer, these options affect that output only if the custom handler uses them.

Change the existing handler when necessary rather than adding a second renderer.

​Custom Rendering and Cleanup Callbacks

The following options replace the corresponding built-in rendering or cleanup function:

OptionCallbackPurpose
renderSuccessfunction()Renders the AJAX success banner.
renderFormErrorsfunction(errors)Renders the error banner. Receives an array of form-level errors.
renderFieldErrorsfunction(errors)Renders field errors. Receives field handles mapped to arrays of validation messages.
removeMessagesfunction()Replaces the normal AJAX message and error-state cleanup.

Freeform binds these callbacks to its plugin instance. Use a regular function if you need to access the instance through this.

The corresponding rendering or cleanup event fires before its callback. If an event listener prevents the default behavior, Freeform skips both the option callback and its built-in implementation.

Use these callbacks or the events documented above when you need custom rendering behavior. Class or message changes alone do not require replacing the renderer.

​Stripe Payments EventsImproved in 5.0+

Use freeform-stripe-appearance to customize Stripe's Payment Element before Freeform creates it.

The event exposes two option objects:

  • elementOptions — options passed to stripe.elements(), including appearance.
  • paymentOptions — options passed when creating the Payment Element, including layout.

Listen on document to customize all Stripe payment fields, or on a specific form element to target that form.

This event bubbles from the Stripe payment field. Unlike Freeform's form events, it does not include event.form or event.freeform.

If needed, find the containing form with event.target.closest('form'). Modify the supplied options to customize initialization; calling event.preventDefault() does not stop it.

​elementOptions.appearance

Use Stripe's Appearance API to customize the Payment Element's theme, variables, and supported styling rules.

Common variables include:

VariableDescription
fontFamilyFont family used by the Payment Element.
fontSizeBaseBase font size used to derive other font sizes.
spacingUnitBase spacing used throughout the interface.
borderRadiusCorner radius for inputs, tabs, and other elements.
colorPrimaryPrimary accent color.
colorBackgroundBackground color.
colorTextText color.
colorDangerError color.

Use appearance.rules for supported Stripe selectors such as .Input, .Label, and .Input:focus.

Stripe supports specific public classes and styling properties. Arbitrary HTML selectors and descendant selectors are not supported. See the Appearance API rules reference for the available options.

​Styling Rules

Use elementOptions.appearance.rules to style Stripe's supported public classes, states, pseudo-classes, and pseudo-elements.

Examples of supported selectors include:

SelectorTargets
.Tab, .Label, .InputTabs, labels, and inputs.
.Tab:focusA focused tab.
.Input--invalid, .Label--invalidInputs and labels in their invalid state.
.Input::placeholderInput placeholder text.

The following selectors are not supported:

SelectorReason
.p-SomePrivateClassPrivate Stripe classes cannot be targeted.
imgArbitrary HTML element selectors are not supported.
.Tab .TabLabelDescendant selectors are not supported.
.Tab--invalidTabs do not support the --invalid state.

Each class supports specific states and CSS properties. See Stripe's Appearance API rules reference for the complete list.

​paymentOptions.layout

Use paymentOptions.layout to configure the Payment Element's layout.

PropertyDescription
typeSelects tabs or accordion.
defaultCollapsedControls whether the element initially appears collapsed.
radiosControls radio indicators in accordion layouts. Stripe currently documents auto, always, never, and if_multiple.
spacedAccordionItemsWhen true, adds space between accordion items.
visibleAccordionItemsCountNumber of accordion items shown before the “More” control. Set to 0 to show all available items. Stripe's documented default is 5.

See Stripe's Payment Element options for the complete reference.

​Examples

These examples customize colors, typography, spacing, borders, labels, focus styles, and the Payment Element's accordion layout.

Register the listener before Stripe initializes the payment field.

Apply the same appearance settings to all Stripe payment fields on the page:

document.addEventListener('freeform-stripe-appearance', (event) => {
const appearance = event.elementOptions.appearance;

appearance.variables = {
...appearance.variables,
colorPrimary: '#0d6efd',
colorBackground: '#1d1f23',
colorText: '#eaeaea',
colorDanger: '#dc3545',
fontFamily: 'system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',
fontSizeBase: '16px',
spacingUnit: '0.2em',
tabSpacing: '10px',
gridColumnSpacing: '20px',
gridRowSpacing: '20px',
borderRadius: '5px',
};

appearance.rules = {
...appearance.rules,
'.Tab, .Input': {
border: '1px solid #6c757d',
boxShadow: 'none',
},
'.Tab:focus, .Input:focus': {
border: '1px solid #0d6efd',
boxShadow: '0 0 0 2px #0d6efd',
transition: 'border-color .15s ease-in-out',
},
'.Label': {
fontSize: '16px',
fontWeight: '400',
},
};

event.paymentOptions.layout = {
...event.paymentOptions.layout,
type: 'accordion',
defaultCollapsed: true,
visibleAccordionItemsCount: 3,
};
});

These examples select the accordion layout because visibleAccordionItemsCount applies only to that layout. Adjust the variables, rules, and layout options to match your site's design.

​Date Picker Events

The Date & Time field can use Freeform's optional flatpickr picker.

When the picker is enabled, use the following events to customize it:

EventPurpose
flatpickr-before-initModify event.options before the picker is created.
flatpickr-readyAccess the created picker through event.flatpickr.

Listen on document to handle pickers across all forms, or on a specific form element to target its pickers.

In 5.17.3+, Freeform also themes pickers automatically for its bundled dark formatting templates. For custom templates, use data-freeform-theme="dark" and override the picker’s CSS variables to match your site. See Date Picker Events for dark/light theme rules, color customization, and examples scoped to one form.

​Autoscroll Events

Customize Freeform's automatic scrolling through the freeform-ready event. This is useful when a fixed header obscures the top of the form or your page uses a scrollable container.

OptionPurpose
scrollOffsetAdjusts the scroll position in pixels. Defaults to 0. A negative value leaves space above the form.
scrollElementSpecifies the window or element to scroll. Defaults to window.

​Adjusting the Scroll Offset

These examples leave 80 pixels above the form to accommodate a fixed header:

document.addEventListener('freeform-ready', (event) => {
event.options.scrollOffset = -80;
});

Adjust -80 to match your header height and the desired spacing.

​Changing the Scroll Target

If your page scrolls inside an element instead of the browser window, use scrollElement to select that container:

document.addEventListener('freeform-ready', (event) => {
const container = document.getElementById('main');

if (container) {
event.options.scrollElement = container;
}
});

The selected element must be a scrollable container. Leave the default window target when the browser page itself scrolls.

Changing the offset or target does not enable automatic scrolling. Configure the relevant scrolling settings in Freeform, or use the Plugin Options.

When Focus First Error After Submit successfully focuses an error, it takes precedence over Freeform's standard AJAX autoscroll.

​Table Field Events

The Table field dispatches events when rows are added or removed through Freeform's controls.

Listen on document to handle events from all forms, or on a specific form element to target that form. Each event includes event.form, event.freeform, and event.table.

EventWhen it firesIncludes event.row
freeform-field-table-on-add-rowBefore the new row is inserted.Yes
freeform-field-table-after-row-addedAfter the new row is inserted.Yes
freeform-field-table-on-remove-rowBefore the row is removed.Yes
freeform-field-table-after-remove-rowAfter the row is removed.No

These events let you customize rows or respond to changes. Calling event.preventDefault() does not stop Freeform from adding or removing a row.

​freeform-field-table-on-add-row

Fires after Freeform prepares the new row's inputs and default values, but before inserting the row into the table.

Use event.row to customize the new row before it appears:

document.addEventListener('freeform-field-table-on-add-row', (event) => {
event.row.classList.add('my-table-row');
});

​freeform-field-table-after-row-added

Fires after the new row has been inserted into the table.

Use this event to initialize custom widgets or interact with the row's inputs. This example focuses the first available input:

document.addEventListener('freeform-field-table-after-row-added', (event) => {
const input = event.row.querySelector(
'input:not([type="hidden"]):not(:disabled), select:not(:disabled), textarea:not(:disabled)'
);

input?.focus();
});

​freeform-field-table-on-remove-row

Fires immediately before a row is removed.

Use event.row to inspect the row or clean up custom widgets attached to it before removal:

document.addEventListener('freeform-field-table-on-remove-row', (event) => {
console.log('Row about to be removed:', event.row);
});

​freeform-field-table-after-remove-row

Fires after a row has been removed.

Use event.table to inspect the remaining rows or update calculations and other interface elements:

document.addEventListener('freeform-field-table-after-remove-row', (event) => {
const rows = event.table.querySelectorAll('tbody > tr');

console.log('Remaining rows:', rows.length);
});

These events describe row additions and removals. Rows already present when the form loads need any custom widget initialization during your normal setup.

​File Upload Drag & Drop Field Events

The File Upload Drag & Drop field provides events for customizing previews, messages, and upload handling.

EventPurpose
freeform-field-dnd-on-render-previewCustomize the preview through event.container. File information is available in event.metadata.
freeform-field-dnd-on-render-preview-remove-buttonCustomize the preview's remove button through event.button.
freeform-field-dnd-render-error-containerCustomize the error element through event.container.
freeform-field-dnd-show-global-messageCustomize a field-level message through event.messageItem.
freeform-field-dnd-on-changeRespond to changes in the field's preview list. The upload field is available through event.container.
freeform-field-dnd-on-upload-progressMonitor upload progress through event.loaded, event.total, and event.percent.
freeform-field-dnd-after-uploadRespond to a successfully uploaded file through event.file. The upload field is available through event.container.
freeform-field-dnd-after-errorsRespond after upload-error handling. Provides event.container and event.messages.

Additional error-handling hooks are available as freeform-field-dnd-append-errors and freeform-field-dnd-clear-errors.

​Upload Progress

Listen on document to monitor uploads across forms:

document.addEventListener('freeform-field-dnd-on-upload-progress', (event) => {
console.log(`Upload progress: ${event.percent}%`);
});

​Completed Uploads

Use this event to respond after an individual file has uploaded successfully:

document.addEventListener('freeform-field-dnd-after-upload', (event) => {
console.log('Uploaded file:', event.file);
});

A completed file upload is separate from a completed form submission. Use freeform-ajax-success with an event.response.finished check when your code should run after the form itself is submitted.

​Save & Continue Later Button Events

Use freeform-save-form-handle-token to customize what happens after the Save & Continue Later button saves an AJAX form's progress.

The event provides:

  • key — the key associated with the saved form state.
  • token — the saved form's session token.
  • url — the URL Freeform will redirect to after saving.

You can modify event.url to change the destination, or call event.preventDefault() to stop the automatic redirect and handle the result yourself.

This event is dispatched directly on the form. Attach your listener to that form element.

​Example

Place this example after a form with the ID my-form. It replaces the automatic redirect with a confirmation message:

<div id="save-status" role="status" aria-live="polite"></div>

<script>
const form = document.getElementById('my-form');

form?.addEventListener('freeform-save-form-handle-token', (event) => {
const status = document.getElementById('save-status');

if (!status) return;

event.preventDefault();
status.textContent = 'Your progress has been saved.';
});
</script>

Preventing the redirect does not undo the saved progress.

​Conditional Rules Events

Use freeform-rules-applied to respond when Conditional Rules change a field or button container's visibility.

The event provides:

  • rule — the rule being applied.
  • target — the affected field or button container.

This event is dispatched on the affected container and does not bubble. Use a capture listener to receive it at document level:

document.addEventListener(
'freeform-rules-applied',
(event) => {
const container = event.target;
const visible = !container.hasAttribute('data-hidden');

console.log('Rule applied:', event.rule);
console.log('Container visible:', visible);
},
{ capture: true }
);

This event reports visibility changes after a rule is applied. It does not fire during the initial rule setup or when the container's visibility remains unchanged.

Calling event.preventDefault() does not undo the visibility change.

​External Script LoadersNew in 5.11.5+

Freeform provides events for external assets inserted through its JavaScript loading helpers. Use them to customize generated tags before insertion or respond after an asset loads.

These events are dispatched on document and expose their properties through event.detail.

EventWhen it firesProperties
freeform-script-before-loadBefore the script tag is inserted.detail.src, detail.script
freeform-script-after-loadAfter the script loads successfully.detail.src, detail.script
freeform-stylesheet-before-loadBefore the stylesheet link is inserted.detail.href, detail.link
freeform-stylesheet-after-loadAfter the stylesheet loads successfully.detail.href, detail.link

​Scripts

This example adds an attribute to Google's reCAPTCHA script tag. Checking the URL's hostname and path allows it to match URLs containing query parameters:

document.addEventListener('freeform-script-before-load', (event) => {
const { src, script } = event.detail;
const url = new URL(src, window.location.href);

if (
url.hostname === 'www.google.com' &&
url.pathname === '/recaptcha/api.js'
) {
script.setAttribute('data-custom-attribute', 'value');
}
});

To run code after an external script loads:

document.addEventListener('freeform-script-after-load', (event) => {
console.log('External script loaded:', event.detail.src);
});

​Stylesheets

Customize a generated stylesheet tag before insertion:

document.addEventListener('freeform-stylesheet-before-load', (event) => {
event.detail.link.setAttribute('data-custom-attribute', 'value');
});

To run code after a stylesheet loads:

document.addEventListener('freeform-stylesheet-after-load', (event) => {
console.log('External stylesheet loaded:', event.detail.href);
});

Register these listeners before Freeform requests the assets. Assets already present in its loader cache do not trigger a new loading cycle.

These events are not cancelable and do not cover every script or stylesheet already included in your page.