Add top-level Integrations control panel navigation for managing CRM, email marketing, element, and other payload integrations outside Settings.
Add site-scoped integrations that can be created and edited on production environments (allowAdminChanges = false). Existing integrations remain project-scoped and deploy via project config.
Add Display Type settings to File Upload fields: File Input (Simple) keeps the native browser input and uploads files on form submit; Upload Manager (Advanced) adds a drag-and-drop zone with async staged uploads, progress, remove, and reorder controls via Formie’s upload endpoints. Existing forms default to File Input (Simple). (#133(opens new window), #2385(opens new window), Discussion #1692(opens new window))
Expose displayType on File Upload GraphQL field settings.
Add per-field Asset Data Retention settings to File Upload fields, allowing uploaded assets to be deleted after a configured duration while the submission record is kept. (#1715(opens new window))
Add File Upload asset retention and stale pending upload cleanup through Craft garbage collection and dedicated console commands.
Dispatch integrations on control panel submission saves when the re-run policy includes Control panel save, including bulk status changes and other direct element saves. CP submission edit saves continue to use the submission workflow without double-triggering. (Discussion #2253(opens new window))
Add IntegrationTriggers service as the single coordinator for workflow, control panel element saves, spam unmark actions, and manual integration runs.
Add IntegrationExecutor service to unify legacy and orchestrated integration step execution, including batched queue jobs.
Add NotificationTriggers service to coordinate status-change email notifications when submission statuses are updated.
Add Use Submission User as Author to Entry element integrations, assigning the collected submission user as the entry author when Collect User is enabled on the form. (#1363(opens new window))
HubSpot Map to Form integrations now resolve custom object objectTypeId values when submitting to HubSpot forms, including portal-specific custom objects (Enterprise). Refresh HubSpot forms after creating custom objects. (#2649(opens new window))
Add Enable Conditions to form integration settings, allowing integrations to be triggered only when submission field and status rules match. (#447(opens new window))
Add Integration Dispatch form settings (Integrations → Settings) to run payload integrations sequentially, choose immediate vs queued execution per integration, control notification timing relative to integrations, and expose dispatch results via {dispatch:handle:property} variables (for example {dispatch:user:url}). Dispatch variables appear in variable pickers when integration dispatch is enabled. (#2635(opens new window), #1152(opens new window), #2810(opens new window))
Add per-notification Dispatch Timing (Advanced) to override the form’s integration dispatch notification timing.
Add configurable Integration API Error Handling for Mailchimp and Campaign Monitor, classifying rate-limited and rejected payloads separately from operational failures. (#2172(opens new window), #1990(opens new window))
Add Integrations::EVENT_AFTER_TRIGGER_INTEGRATION_FAILED for handling integration failures outside the queue, and Send Email Alert for Failed Integration settings mirroring failed notification alerts. (Discussion #2579(opens new window))
Changed
Apply control panel submission sidebar fields (title, status, spam, mark as complete) during managed CP submission saves.
Route all integration trigger entry points through IntegrationTriggers instead of Submission::afterSave hooks.
Consolidate legacy and orchestrated integration dispatch behind IntegrationExecutor, using batched TriggerIntegration queue jobs for queued steps.
Route status-change email notifications through NotificationTriggers instead of inline logic in Submission::afterSave.
Deprecate Formie 3 Submissions integration and notification dispatch helpers when compatibility mode is enabled. Use Notifications, Integrations, and IntegrationTriggers instead.
Remove unused Integration::shouldTriggerOnSubmissionEdit() API (superseded by re-run policies).
Update phone number values sent to integrations to use E164 format instead of international formatting. (Discussion #2731(opens new window))
Improve integration queue job descriptions and debug output with form context (formId, formHandle, formTitle). (#2172(opens new window))
Reorganise plugin settings: move integration behaviour settings to Settings → Behavior → Integrations, and move Use Queue for Notifications to Email Notifications.
OAuth integration redirect URIs now default to a Craft action URL instead of a site URL. Add an optional OAuth Redirect URI Override plugin setting. (#1333(opens new window))
Fixed
Fix Opayo, Stripe, Paddle, and GoCardless payment integrations not resolving Billing Details field mappings from the form builder static table, so Name and Address fields are included in payment payloads again. (#2617(opens new window))
Fix Salesforce integrations failing after Craft 5 / Formie 3 upgrades when OAuth tokens were migrated without instance_url, by falling back to stored integration settings and backfilling token values. (#2492(opens new window))
Fix Salesforce integration refresh failing when an enabled object such as Opportunity or Case is unavailable in the connected org. (#1551(opens new window))
Fix Marketo OAuth connect failing when an empty scope parameter is sent with the client-credentials grant, and normalize API domains that include a trailing /rest segment. (#2718(opens new window))
Fix Mailchimp integrations not exposing or formatting Address merge fields, which prevented mapping Formie Address fields to Mailchimp audiences that require ADDRESS data. (#2387(opens new window))
Improve Pardot integration errors when an account does not support API v4 (legacy Pardot Classic). (#2642(opens new window))
Fix file upload assets being deleted when trashing a submission with File Uploads → Delete files enabled, so restored submissions keep their uploaded files. (#1258(opens new window))
Fix new File Upload fields defaulting to an empty Email Field Summary Value setting.
Fix Signature fields intermittently showing a misleading “browser does not support” message on multi-page forms, conditional fields, and late layout by retrying canvas sizing, watching visibility changes, and showing accurate status copy when initialization fails. (#2708(opens new window))
4.0.0-beta.5 2026-06-12
Added
Add a Template default value source for Hidden fields using sandboxed Craft object templates. Resolved server-side on render and submit; posted values are ignored. Custom Value behaviour is unchanged. (#2605(opens new window))
Add rich text editing for field Instructions, including Craft entry links with target="_blank", configurable via rich-text.json under fields.instructions. Legacy plain-text and markdown instructions are normalized automatically without migration. (#724(opens new window))
Add Craft-style attribute maps and merge helpers for setFieldSettings() field overrides, including mergeInputAttributes and mergeContainerAttributes. (#2510(opens new window))
Add a Note builder field for form-builder guidance with Tip, Warning, Info, and Error styles. (#2498(opens new window))
Add a syntax-highlighted HTML code editor for HTML cosmetic fields in the form builder, with project config via html.json. (#2181(opens new window))
Add an Allow Twig setting to HTML fields, controlling whether Twig is parsed when rendering field content. Twig runs in Formie’s sandboxed template environment, not Craft’s full CP template stack.
Add a Custom Field form-builder field backed by opt-in Craft field adapters. (#2208(opens new window))
Add Craft Link field support for Custom Field field, covering URL, email, phone and SMS link values. (#718(opens new window))
Add dynamic Option Source settings for Dropdown, Radio and Checkboxes, allowing options to be populated from predefined option sets and other structured sources. (#2684(opens new window))
Add integration option sources, allowing integrations to opt in and expose selectable remote option lists to Dropdown, Radio and Checkboxes fields. (#512(opens new window))
Add Mailchimp option sources for Interest Categories and Tags, using cached integration form settings and manual refresh actions from the field settings UI. (#512(opens new window))
Add CRM integration option sources for HubSpot (forms and CRM properties), Salesforce, Zoho, and Microsoft Dynamics 365 picklists. (#512(opens new window))
Add Template option source mode for developer-owned option lists supplied at render time without persisting or strictly validating an authoritative option list.
Add a Use Searchable Dropdown setting for Dropdown fields, element relation fields when Display type is Dropdown, and Recipients when shown as a dropdown. The front end loads Formie’s combobox browser module so users can filter predefined options. (#960(opens new window))
Add support for changing compatible field types in the form builder, initially limited to simple string-like fields such as Single-Line Text and Email Address. Existing submissions are not rewritten. (Discussion #2110(opens new window))
Add Settings → Fields → Field Builder policy settings for Allow Multi-Select Dropdowns and Allow Phone Country Selector. When disabled, the corresponding field settings are hidden in the form builder and forced off on existing fields. (Discussion #2484(opens new window), Discussion #2485(opens new window))
Expose the Allow Public Asset Volumes plugin setting in Settings → Fields, controlling whether File Upload fields can use public asset volumes and whether Public URL is available as an email summary value.
Add Date Range collection to Date/Time fields when Display Type is Calendar (Advanced), using Flatpickr range mode to collect a start and end date/time. (#2011(opens new window))
Add an includeFlatpickrCss plugin setting to disable Formie’s bundled Flatpickr stylesheet when your project already provides its own. (#2341(opens new window))
Add notification variable selectors for date ranges, including Start Date/Time, End Date/Time, Start Date, Start Time, End Date, and End Time.
Add GraphQL content types for date range submissions with start and end datetime values.
Add calendar date validation for Date/Time Text Inputs and Dropdowns, rejecting impossible dates (for example February 31), enforcing configured Min Date / Max Date settings on those display types, and surfacing validation errors on the offending sub-field. (#1458(opens new window))
Add smart State / Province behaviour for Address fields, with Text or Dropdown when available input modes, country-dependent subdivision loading, dynamic labels (State, Province, Prefecture, and so on), optional hiding when unused, searchable dropdowns, and datalist suggestions for text fallback. (#1416(opens new window))
Add a subdivisions endpoint (formie/address/subdivisions) and ModifyAddressSubdivisionsEvent for country-dependent state/province option data.
Add an address-state browser module with lazy subdivision loading, loading UX (country spinner and state skeleton), and password-manager/browser autofill reconciliation via a persistent address-level1 anchor input.
Add Allowed Countries and Preselect Country from IP settings to Address fields, mirroring Phone field country restrictions and using a shared formie/address/country-from-ip endpoint (CDN geo headers such as CF-IPCountry).
Add Preselect Country from IP to Phone fields when the country selector is enabled, wiring intl-tel-input geo lookup through the shared country-from-ip endpoint.
Add table column reference support for Calculations fields with explicit row scope (first, last, index, all, count, custom row expressions). Table columns now appear in the Calculations variable picker, with row targeting configured in the variable settings popover. (#1284(opens new window))
Add Settings → Synced Fields as a read-only audit page listing shared field definitions and the forms they appear on, with a View usage link from synced fields in the form builder. (#2377(opens new window))
Changed
Refactor predefined options to align with the new option sources system.
Improve HTML and Rich Text cosmetic field builder previews and control panel submission views to show rendered output instead of raw source where appropriate. (#2182(opens new window))
Render HTML field builder previews inside a sandboxed iframe so control panel styles do not bleed into preview content.
Render HTML field Twig through Formie’s sandboxed template service instead of Craft’s unrestricted renderString(), and default Allow Twig to off for new HTML fields.
Respect Include in Email Field Summaries for cosmetic fields in {allFields}, {allContentFields}, and {allVisibleFields} instead of always excluding them.
Update @verbb/plugin-kit-react to 1.0.4 for the CodeMirror-based HTML editor, codeEditor SchemaForm field registration, and live Rich Text preview rendering via TiptapContent.
Normalise Address sub-field browser selectors to the data-formie-address-* namespace, with legacy short-selector fallbacks for older saved forms and address provider modules.
Default new Address field layouts to place Country before State / Province so dependent subdivision loading works out of the box.
Map Freeform Rich Text fields to Formie Rich Text rather than HTML during migration.
Replace the Dropdown, Radio and Checkboxes option-table Disabled column with a row-menu Visible / Hidden / Disabled availability control (#1816(opens new window)). Hidden removes an option from the front-end form while preserving stored submission values and labels; Disabled renders the option with HTML disabled so it stays visible but cannot be selected. Legacy disabled: true option rows are treated as hidden. Non-default states are indicated in the options table with row background tints.
Centralise front-end option filtering in OptionsField::getFieldOptions() so hidden options are excluded consistently (including Dropdown placeholders).
Format Date/Time values consistently for notifications, summaries, exports, and string output using the field's Date Format and Time Format settings. Casting a normalized date value object to string now matches getFieldValueAsString().
Update integration field mapping to accept Date/Time reference values with text, date, and number types.
Move Agree field checked/unchecked display labels to the Settings tab and clarify that submissions store a boolean; use getFieldValueAsString() for Yes/No-style output. (#2288(opens new window))
Normalise submission values by trimming leading and trailing whitespace during field normalization for single-line text, email, plain multi-line text, hidden, phone, number, name, address, and custom string fields. Password fields and rich text content are unchanged; existing submissions keep their stored values until resaved.
Deprecated
Deprecate the PredefinedOptions service, predefined option class namespace (verbb\formie\options\*), and PredefinedOptions::EVENT_REGISTER_PREDEFINED_OPTIONS event registration target. Use OptionSources, predefined option classes under verbb\formie\options\predefined\*, and OptionSources::EVENT_REGISTER_PREDEFINED_OPTIONS instead. Legacy APIs remain available through the compatibility layer with deprecation notices.
Fixed
Fix page-reload single-line and multi-line text limit validation rerenders so field error styling, form-level error messages, and scroll/focus behaviour match ajax submissions. (#1997(opens new window))
Fix Recipients fields preserving the selected option label when multiple recipient options send to the same email address, using encrypted row identity tokens while keeping recipient emails private in front-end markup. (#2382(opens new window))
Fix static Recipients option rows accepting invalid email targets by validating each comma-separated recipient address in the field settings.
Fix Dropdown, Radio and Checkboxes Disabled option availability not outputting HTML disabled on the front-end form. (#1816(opens new window))
Fix Address and other fixed-parent sub-field settings being unavailable in the form builder by restoring on-demand field type config loading for nested sub-field types. (#1416(opens new window))
4.0.0-beta.4 2026-06-07
Added
Add conditional submission status rules in the form builder Settings → Submissions tab, evaluated on the front end during submission processing. (#508(opens new window))
Add conditional redirect rules under Behaviour → After Submit, with an optional Enable Redirect Rules toggle that overrides the default submit action when conditions match. (#830(opens new window))
Add failed notification alert recipients by Craft user group and additional email addresses. (#2226(opens new window))
Add per-rule validation message overrides via a Validation form builder tab and the validationMessages field setting, with legacy errorMessage values migrated to validationMessages.required. (#1269(opens new window))
Add plugin-wide default validation message templates under Settings → Defaults → Field Defaults.
Add ValidationMessagesHelper and client data-formie-validation-{key}-message attributes for overridden validation copy on the front end.
Add unique-value, match-field, text-limit, number-limit, email-format, blocked-domain, options-limit, and file-upload validation message overrides on supported field types. (#1475(opens new window))
Changed
Standardize validation message placeholders to {label} across PHP validators, front-end validators, and translations (legacy {name} / {attribute} aliases remain at runtime).
Replace text-limit counter {startTag}{num}{endTag} translation strings with Craft plural syntax and wire translated counter copy on the front end. (#2526(opens new window))
Show context-aware text-limit counter copy for empty (allowed), under-limit (left), and over-limit states on the front end and in control panel submissions.
Add per-field validation error position on the Appearance tab, with form- and plugin-level defaults (Above Input / Below Input).
Resolve nested Date/Name/Address sub-field validation messages from their parent field; stop copying legacy errorMessage onto Date sub-fields.
Wire client-side validation message overrides for file-upload and checkbox/radio options-limit rules via data-formie-validation-*-message attributes.
Extend front-end t() to resolve Craft-style {param, plural, …} and {param, number} message syntax.
Fixed
Fix option field values appearing empty in notification “All Form Fields” summaries when options were overridden via Twig setFieldSettings(), by applying persisted submission snapshots when loading forms for email/export and falling back to stored option values when labels cannot be resolved. (#2350(opens new window))
Fix submission status filters in the control panel returning no results when submissions were saved without a persisted statusId, and resolve status queries by display name as well as handle. (#2687(opens new window))
Sanitize notification queue job debug data to valid UTF-8 before re-serializing failed jobs, preventing queue rows from becoming unreadable when submission content contains invalid byte sequences. (#2344(opens new window))
Improve notification mailer failure logging when Craft returns no transport error message, including CLI/queue context to help diagnose cron-only send failures. (#2610(opens new window))
4.0.0-beta.3 2026-06-06
Added
Add a configurable field palette for the form builder, with drag-and-drop group and field organisation, per-field enable/disable, and optional palette label overrides. Replaces the legacy Disabled Field Types settings checkboxes. (#2209(opens new window))
Add a stock Form Preview slide-out in the form builder, rendering the current form with Formie’s default templates, CSS, and JavaScript. (#370(opens new window))
Add stencil scopes so developers can ship starter forms in project config while content editors can create and manage their own stencils in the control panel. (#2814(opens new window))
Add project stencils (stored in formie.stencils project config) alongside regular database-backed stencils, with handles unique across both scopes.
Add the formie-accessStencils permission for managing stencils in the control panel.
Add read-only viewing of project stencils when admin changes are disabled, with Save a copy to create an editable stencil.
Add a Type column to the stencils index, showing Project for project stencils only.
Add a dedicated Settings → Defaults control panel page for form, field, and notification defaults. (#863(opens new window))
Add structured formDefaults, fieldDefaults, and notificationDefaults plugin settings, applied when new forms, fields, and notifications are created.
Add supportedDefaults() and schema extraction for field-type defaults, with Date, File Upload, Phone, Agree, Single-Line Text, Multi-Line Text, Email, Number, Hidden, Radio, Checkboxes, and element fields (Entries, Categories, Users, Tags, Products, Variants) as supported field types.
Add Field Defaults developer documentation for third-party field authors.
Add schema-driven form and notification defaults extracted from the form builder and notification schemas, including a PDF template default for new notifications.
Add captcha integration defaults for new forms and stencils via integrationDefaults.
Add a migration to move legacy defaultFileUploadVolume, defaultDateDisplayType, defaultDateValueOption, and defaultDateTime settings into fieldDefaults.
Track and display who created and last updated a form in the form builder Settings tab footer and as optional forms index columns. (Discussion #2342(opens new window))
Add submission UID to the control panel submission sidebar and as an optional submissions index column. (#2404(opens new window))
Add an Autocomplete setting to single-line and multi-line text fields in the form builder Settings tab, with a searchable list of HTML autocomplete tokens. (Discussion #2764(opens new window))
Document using {env:FORMIE_*} environment variable tokens in notification recipient fields. (#2676(opens new window))
Add an opt-in setting to disable the submit button until the current page passes validation. (#1514(opens new window))
Add a page setting to place the submit button at the end of the last field row. (#2542(opens new window))
Add regression tests for required File Upload fields submitted via GraphQL with base64 file data. (#1130(opens new window))
Add control panel submission field condition behaviour with plugin and per-form settings to follow, collapse, or ignore front-end field and page conditions when editing submissions. (#2435(opens new window))
Changed
Replace Settings → Fields disabled-field checkboxes with the new field palette editor.
Move stencil management from Settings to Formie → Stencils, including create, edit, and index routes under formie/stencils/*. Legacy formie/settings/stencils/* URLs redirect to the new paths.
Change Save as stencil from the form builder to always create an editable, database-backed stencil.
Fixed
Fix legacy upgrade migrations failing on fresh Craft 5 installs that never had Craft’s content or formie_tokens tables.
Fix form usage counts and the form builder Usage tab omitting entries on disabled Craft sites. (#2612(opens new window))
Fix the form builder Usage tab not listing elements that reference a form on non-primary sites, including when Craft stores a relation without a specific sourceSiteId. (#2695(opens new window))
Prompt for confirmation when closing a field settings overlay with Escape (or backdrop/header close) only when the field has unsaved changes. Untouched new fields close immediately. (#2219(opens new window))
Fix dropdown field options not saving in the form builder when no default option is selected. (#2795(opens new window))
Validate literal email addresses in notification recipient settings so invalid addresses are caught when saving notifications. (#2712(opens new window))
Skip notification email attachments when the asset file cannot be read, instead of failing the entire send. (#2626(opens new window))
Fix replacing a deleted field with a new field using the same handle requiring a two-step save in the form builder. (#1854(opens new window))
Fix checkbox fields saving their default option values when explicitly unchecked on submit. (#2457(opens new window))
Fix missing page-list validation indicators in the form builder when a form has no pages. (#2786(opens new window))
Add a default country setting for Google Places address auto-complete fields. (#2721(opens new window))
Fix email notification preview failing when a recipient setting references a non-email field. (#2537(opens new window))
Add a configurable maximum email attachment size, and validate notification attach assets in the form builder. (#2697(opens new window))
Fix file upload validation allowing extensions such as .jfif that Craft cannot save as assets. (#2716(opens new window))
Fix the Dutch translation mapping Auto to Automatisch, which incorrectly changed checkbox labels and values meaning “car”. (#2636(opens new window))
Generate translatable date picker placeholders from the configured date and time formats when no custom placeholder is set. (#2464(opens new window))
Fix File Upload fields failing on submit when no upload location is set, by requiring the setting in the form builder and falling back to the plugin default volume when configured. (#2597(opens new window))
Fix File Upload fields inside Repeater or Group fields not initializing upload persistence for nested inputs. (#1448(opens new window))
4.0.0-beta.2 2026-06-03
Fixed
Fix front-end JS/CSS build issues.
Fix ModifyFrontendJsTranslationsEvent naming.
4.0.0-beta.1 2026-06-02
Added
Add a Formie 3 to Formie 4 migration path for existing Craft 5 projects.
Add direct Formie 2 to Formie 4 migration support, allowing Craft 4 projects to move to Craft 5 without upgrading through Formie 3 first.
Add Formie 4 Compatibility Mode, enabled by default, to bridge selected Formie 3 class aliases, event owners, custom field schema methods, field config keys, theme config keys, and legacy front-end event listeners during upgrades.
Add the new React-powered form builder foundation.
Add schema-driven integration settings for the form builder via Integration::defineFormSettingsSchema(), Integration::getFormSettingsSchema(), Integration::EVENT_MODIFY_INTEGRATION_FORM_SETTINGS_SCHEMA, and ModifyIntegrationFormSettingsSchemaEvent.
Add Notifications::EVENT_MODIFY_NOTIFICATION_SCHEMA for modifying notification schemas.
Add a new staged submission workflow service (SubmissionWorkflow) with prepare, normalize, validate, screen, authorize, save, dispatch, and finalize stages.
Add submission workflow process modes for normal submits, existing-submission edits, save-draft requests, and payment replays.
Add SubmissionRequestEvent, SubmissionWorkflowStageEvent, SubmissionWorkflowTaskEvent, RegisterWorkflowStagesEvent, and RegisterStageTasksEvent.
Add workflow enums for stage and task names, including tasks such as screen.runCaptchaChecks, save.processPayments, dispatch.sendNotifications, and dispatch.triggerIntegrations.
Add database-backed temporary submission state, incomplete submission state, saved drafts, and resume-token handling.
Add save-and-resume retention settings including submissionStateRetentionDays, saveResumeTokenTtlDays, and maxSavedDraftsPerSession.
Add anonymous client bootstrap and refresh rate-limit settings: anonymousClientBootstrapRateLimit, anonymousClientRefreshRateLimit, and anonymousClientRateWindowSeconds.
Add static-cache token refresh handling with staticCacheRefreshOnLoad.
Add setOnlyCurrentPagePayload for limiting submitted multi-page payload handling to the current page.
Add plainTextHtmlSanitizationMode for controlling plain-text HTML sanitization behavior.
Add useCssLayers for optionally outputting Formie CSS with CSS layers.
Add a Formie-native submission content manager, normalizer, serializer, and accessor layer.
Add field definition metadata APIs and traits for Formie-owned field definitions.
Add Field::getDescription() description sections for field value, structure, component, behavior, references, and conditions metadata.
Add Field::themeConfigKey() for resolving canonical theme config field keys.
Add Field::defineValueForReference(), Field::getValueForReference(), Field::defineValueForReferenceBlock(), and Field::getValueForReferenceBlock() as the canonical field reference value APIs.
Add Field::defineValueForCondition() and Submission::getFieldValueForCondition() for condition-specific value projection.
Add Field::getCpEditHtml() as the canonical CP submission edit rendering contract.
Add Field::defineFieldSlotTag() and SlotTag for field slot tag customization.
Add Form::EVENT_MODIFY_SLOT_TAG, Field::EVENT_MODIFY_SLOT_TAG, and Integration::EVENT_MODIFY_SLOT_TAG.
Add ModifyFormSlotTagEvent, ModifyFieldSlotTagEvent, and ModifyIntegrationSlotTagEvent.
Add Field::EVENT_MODIFY_VALUE_FOR_REFERENCE and Field::EVENT_MODIFY_VALUE_FOR_REFERENCE_BLOCK.
Add ValueContext::array(), ValueContext::reference(), and ValueContext::referenceBlock().
Add craft.formie.parseValue() and craft.formie.parseContent() for parsing field-reference values in Twig.
Add craft.formie.formAssets() for form-scoped asset output.
Add craft.formie.frontendAssets() for shared front-end asset output.
Add new FormTemplate output locations: PAGE_HEADER, PAGE_FOOTER, INSIDE_FORM, and MANUAL.
Add initJs and useObserver rendering options for controlling Formie front-end initialization.
Add client/server rendering services for Formie-managed HTML and client-rendered consumers, including ClientSessionService, FormBootstrapBuilder, FormDefinitionBuilder, ClientModuleManifestBuilder, and ServerRenderPayloadBuilder.
Add client request/response models including FormSession, LoadContext, FormDefinition, FormBootstrap, SubmitRequest, PageTransitionRequest, SessionRefreshRequest, and SubmitResult.
Add client controllers for loading forms, changing pages, refreshing sessions, and submitting client-rendered forms.
Add FrontendAssets as the canonical shared front-end asset service.
Add ClientModule, ClientModuleContext, and RenderFrame models.
Add IntegrationInterface::getClientModule() for front-end module registration by integrations, captchas, address providers, and payments.
Add ClientModule manifests with render-target metadata for front-end module hydration.
Add hydrateFormieModules() support for hydrating individual Formie modules without mounting a full form client.
Add the @verbb/formie-core package for framework-agnostic form definitions, transports, field helpers, conditions, calculations, and client-rendered form state.
Add the @verbb/formie-browser package as Formie’s canonical browser runtime for server-rendered forms.
Add the @verbb/formie-react package with FormieForm, FormieClientForm, useFormieHtml(), useFormieClient(), useFormie(), useFormieField(), useFormiePage(), useFormieInstance(), and useFormieSlot().
Add the @verbb/formie-vue package with matching server-rendered and client-rendered Vue APIs.
Add the @verbb/formie-web-components package with formie-form, formie-core-form, registerFormieWebComponents(), FormieRegistry, and createFormieRegistry().
Add REST and GraphQL transports for client-rendered forms.
Add createFormieClient(), formie(), FormieValidator, ModuleRegistry, defineCaptchaModule(), definePassiveCaptchaModule(), definePaymentModule(), and defineAddressModule() to the browser package.
Add browser CSS exports for Formie’s base, theme, and combined CSS.
Add canonical formie:* browser events for mount, unmount, validation, submit, page navigation, token refresh, state reset, field modules, address modules, payment modules, and submission workflow stages.
Add the canonical formie:client:ready event.
Add page-level client analytics output via data-formie-client-event.
Add GraphQL formieHtmlForm for server-rendered HTML form payloads.
Add GraphQL formieClientForm for client-rendered form definitions and sessions.
Add GraphQL mutations for client-rendered form submit, page changes, and session refresh.
Add GraphQL runtimePayload/client payload support built from the shared front-end payload builder.
Add GraphQL schema scope enforcement for handle-based client form reads and lifecycle mutations.
Add support for nested GraphQL field builders to read stored row configs for Group, Repeater, and Table-style fields.
Add request-local caches for form lookups, field metadata, field config settings, client module manifests, integration lists, submission status handles, and GraphQL field metadata.
Add synced-field storage split between shared field definitions and per-form field placements.
Add migration support for synced-field definitions and placements.
Add blocking validation for synced-field handle collisions instead of silently renaming handles.
Add support for detaching synced fields.
Add field-reference preservation for unresolved historical submission content when fields are removed or layouts change.
Add support for preserving Name field multi-part layout values when field modes change.
Add SubmissionQuery::invalidateStaticCaches() for long-running workers after form/field mutations.
Add Formie::$plugin->getFactories() for programmatic form and submission builders.
Add security regression guard tests.
Add a performance harness for submission query and field-graph scenarios.
Add integration field-mapping regression coverage across complex and nested field values.
Add Formie 4 plugin docs, migration docs, developer docs, and front-end package docs.
Add React, Vue, Web Components, Next.js, and Nuxt starter projects for the new front-end package stack.
Add Craft-rendered starter examples for Barba.js, Sprig, and Datastar.
Add @verbb/plugin-kit and @verbb/plugin-kit-react as the shared control panel UI foundation used by Formie’s React builder.
Changed
Require Craft CMS 5 and PHP 8.2+.
Rework Formie’s form builder around React, schema-driven settings, and shared Plugin Kit React components.
Rework Formie’s front-end JavaScript from the old bundled theme/runtime model to package-based browser and framework runtimes.
Split Formie’s front-end rendering model into server-rendered forms and client-rendered forms.
Move Formie browser JavaScript and CSS into @verbb/formie-browser.
Rename @verbb/formie-dom to @verbb/formie-browser.
Replace old Formie JavaScript callback names and validator events with canonical formie:* DOM events.
Move the public ready event from formie:runtime:ready to formie:client:ready.
Move runtime/client PHP namespaces toward client naming, while keeping selected runtime class aliases in Compatibility Mode.
Rename runtime JS translation hooks to frontend JS translation hooks: Rendering::EVENT_MODIFY_FRONTEND_JS_TRANSLATIONS, ModifyFrontendJsTranslationsEvent, and Rendering::getFrontendJsTranslations().
Replace RuntimeModule and RuntimeModuleContext terminology with ClientModule and ClientModuleContext.
Replace RuntimeRenderFrame terminology with RenderFrame.
Rename RuntimeAssets to FrontendAssets.
Replace renderFormAssets(), registerFormAssets(), renderFormCss(), and renderFormJs() with formAssets().
Replace renderRuntimeAssets(), renderCss(), and renderJs() with frontendAssets().
Rename render options renderCss and renderJs to includeCss and includeJs.
Rename form template options outputCssLayout and outputCssTheme to outputCss.
Rename form template options outputJsBase and outputJsTheme to outputJs.
Change Formie’s default front-end CSS class prefix from fui to formie.
Change form submit processing from a single save-oriented path to the staged submission workflow.
Route controller submissions, managed client submissions, GraphQL submissions, save-draft requests, and payment replays through the same submission workflow engine.
Move payment processing into workflow tasks instead of calling standalone submission payment processing directly.
Move notification dispatch and integration dispatch into workflow dispatch tasks.
Move payment callbacks, webhooks, and status polls through the payment replay workflow path with idempotent handling.
Store temporary and incomplete submission state in the database instead of offering session/database progression storage modes.
Remove the old user-facing submissionStore/submissionStateMode choice from active submission progression behavior.
Refresh submission state tokens on each multi-page step and Ajax response.
Use encrypted/authenticated state tokens for multi-page progression.
Rework save-and-resume around tokenized database records, TTL handling, capability checks, and URL token stripping.
Rework pending upload handling around sidecar records, finalize-on-submit behavior, and garbage collection of stale uploads.
Change submit action URLs and hidden field initial values so they no longer execute Twig.
Separate field defaults from prefill sources.
Change the default submission title pipeline to use submissionTitleFormat and field references on first save.
Change field references to use stable field references instead of relying only on field handles in places such as notifications, calculations, conditions, and integration mapping.
Change field value APIs from JSON/variable/email terminology toward array/reference/reference-block terminology.
Change field value storage and projection to preserve unresolved historical field UIDs instead of dropping unknown values after layout changes.
Change CP submission editing to hydrate only required field modules rather than mounting an entire front-end form client.
Change condition evaluation to use explicit boolean, numeric, and string coercion.
Change container and repeatable field condition subjects to use handle keys while storage remains UID-keyed.
Change field type metadata and GraphQL metadata to read from normalized configs before materializing field objects.
Change Formie fields service internals to stay config-first until callers need field object traversal.
Change Formie form, field, integration, and GraphQL lookup hot paths to use request-local caches.
Change synced fields from self-referential syncId fan-out to a definition/placement storage model.
Lock synced-field handle edits while fields remain synced.
Change stencils to use the canonical React builder and snapshot semantics.
Change stencil form creation to remap field references when materializing forms.
Change integration settings in the form builder from Twig/Vue HTML to PHP-defined schemas.
Change custom integration front-end output from getFrontEndJsVariables() to client modules.
Change address providers, captchas, payments, and field modules to register browser modules via the new client module manifest.
Change captchas to run through the workflow screen stage.
Change passive captcha and spam checks to use the shared screen workflow stage.
Change Formie’s static-cache support to use built-in token refresh behavior instead of requiring custom refresh snippets.
Change headless form rendering to use explicit server-rendered and client-rendered GraphQL queries.
Change GraphQL formieForm { templateHtml } usage to formieHtmlForm { html }.
Rename GraphQL page client event settings from enableJsEvents and jsGtmEventOptions to enableClientEvents and clientEventFields.
Change GraphQL field metadata generation to use cached field metadata from the fields service.
Change GraphQL client-form access so handle-based reads and lifecycle mutations require explicit schema scopes.
Change custom field schema method names from defineGeneralSchema(), defineSettingsSchema(), defineAppearanceSchema(), defineAdvancedSchema(), and defineConditionsSchema() to defineFormBuilderGeneralSchema(), defineFormBuilderSettingsSchema(), defineFormBuilderAppearanceSchema(), defineFormBuilderAdvancedSchema(), and defineFormBuilderConditionsSchema().
Change schema node keys from $formkit to $field.
Change schema help text keys from help to instructions.
Change field builder previews from getFormBuilderPreviewHtml() to defineFormBuilderPreviewSchema().
Change field input template discovery from getFrontEndInputTemplatePath() to getInputTemplatePath().
Change field email template terminology from email templates to reference-block templates.
Change field slot/tag customization from HtmlTag/htmlTag terminology to SlotTag/slotTag.
Change form render IDs from Form::getFormId()/setFormId() terminology to Form::getRenderId()/setRenderId().
Move Submissions::EVENT_BEFORE_SEND_NOTIFICATION ownership to Notifications::EVENT_BEFORE_SEND_NOTIFICATION.
Move Submissions::EVENT_BEFORE_TRIGGER_INTEGRATION ownership to Integrations::EVENT_BEFORE_TRIGGER_INTEGRATION.
Keep Yii-style getElementValidationRules() as the supported submission validation surface for Formie 4.
Update integration field mapping to handle nested groups, repeaters, tables, element fields, and normalized field values more consistently.
Improve payment webhook, callback, and status-poll error handling and authenticity checks.
Improve anonymous runtime route method constraints and abuse/rate-limit handling.
Improve CORS handling so arbitrary origins are not reflected when GraphQL origins are not configured.
Improve large-form builder drag/drop performance and validation in production builds.
Improve export/query performance with request-local caches and explicit invalidation hooks.
Fixed
Fix migration coverage for Formie 3 to Formie 4 upgrades.
Fix migration coverage for direct Formie 2 to Formie 4 upgrades.
Fix synced-field migration to preserve shared field definitions and per-form placements.
Fix field hydration for legacy config keys under Compatibility Mode.
Fix legacy webhook/automation naming compatibility during upgrades.
Fix Stripe and other payment replay flows to run through the canonical workflow path.
Fix submission workflow failure logging to include halted stage, stage metadata, payment status, payment message, and payment decision details.
Fix hidden condition values and container/repeatable field values to use normalized field value projections consistently.
Fix condition evaluator behavior for boolean, numeric, and string comparisons.
Fix unresolved historical submission data being lost when a form layout no longer contains the original field.
Fix GraphQL schema generation for nested field structures.
Fix GraphQL field metadata generation performance for large forms.
Fix form handle lookup hot paths by routing through request-local form caches.
Fix repeated per-form integration list resolution by memoizing enabled integrations per form per request.
Fix client module manifest lookup costs with request-local caches.
Fix long-running worker cache staleness by exposing SubmissionQuery::invalidateStaticCaches().
Fix file-upload security checks for MIME types, extensions, active content, and filename normalization.
Fix safer file upload URLs in CP and email summary contexts.
Fix payment webhook and callback responses to avoid exposing sensitive validation details.
Fix anonymous client bootstrap, refresh, page transition, and submit flows to share stricter abuse controls.
Fix static-cache handling for token refresh and restored form responses.
Fix large builder drag/drop behavior on dense multi-page forms.
Fix integration mapping for normalized nested field values.
Fix missing or inconsistent custom field compatibility for legacy schema arrays and FormKit-style nodes.
Fix legacy front-end event bridging for projects migrating from Formie 3 event listeners.
Deprecated
Deprecated Form::getFormId() and Form::setFormId(). Use Form::getRenderId() and Form::setRenderId().
Deprecated Form::EVENT_MODIFY_HTML_TAG. Use Form::EVENT_MODIFY_SLOT_TAG.
Deprecated ModifyFormHtmlTagEvent. Use ModifyFormSlotTagEvent.
Deprecated Field::EVENT_MODIFY_HTML_TAG. Use Field::EVENT_MODIFY_SLOT_TAG.
Deprecated ModifyFieldHtmlTagEvent. Use ModifyFieldSlotTagEvent.
Deprecated Field::EVENT_MODIFY_VALUE_AS_JSON. Use Field::EVENT_MODIFY_VALUE_AS_ARRAY.
Deprecated Field::EVENT_MODIFY_VALUE_FOR_EMAIL. Use Field::EVENT_MODIFY_VALUE_FOR_REFERENCE_BLOCK.
Deprecated field value JSON methods such as getValueAsJson() and defineValueAsJson(). Use array-based equivalents.
Deprecated field variable value methods such as getValueForVariable(), getValueForVariableRaw(), defineValueForVariable(), and defineValueForVariableRaw(). Use reference value methods.
Deprecated field email value methods such as getValueForEmail() and defineValueForEmail(). Use reference-block value methods.
Deprecated field email template methods such as getEmailTemplatePath(), getEmailHtml(), getEmailOptions(), hasEmailLabel(), and hasEmailPlaceholder(). Use reference-block equivalents.
Deprecated legacy field key helpers such as getFieldKey(), getErrorKey(), getFullHandle(), getFullNamespace(), and getReservedHandles().
Deprecated legacy custom field schema methods in favor of defineFormBuilder*Schema() methods.
Deprecated getFormBuilderPreviewHtml() in favor of defineFormBuilderPreviewSchema().
Deprecated getFrontEndInputTemplatePath() in favor of getInputTemplatePath().
Deprecated defineHtmlTag() in favor of defineFieldSlotTag().
Deprecated Submission::getValueAsString(), Submission::getValueAsJson(), Submission::getValueForExport(), and Submission::getValueForSummary() in favor of getFieldValue*() methods.
Deprecated Submission::getFieldValueAsJson() in favor of Submission::getFieldValueAsArray().
Deprecated Submission::getValuesAsJson() in favor of Submission::getValuesAsArray().
Deprecated Submission::getFieldValueForEmail() in favor of Submission::getFieldValueForReferenceBlock().
Deprecated Submission::getFieldValueForVariable() in favor of Submission::getFieldValueForReference().
Deprecated SubmissionContentManager::getValuesAsJson() in favor of getValuesAsArray().
Deprecated ValueContext::json() and ValueContext::TYPE_JSON. Use ValueContext::array() and ValueContext::TYPE_ARRAY.
Deprecated ValueContext::variable() and ValueContext::TYPE_VARIABLE. Use ValueContext::reference() and ValueContext::TYPE_REFERENCE.
Deprecated ValueContext::email() and ValueContext::TYPE_EMAIL. Use ValueContext::referenceBlock() and ValueContext::TYPE_REFERENCE_BLOCK.
Deprecated craft.formie.registerAssets(), craft.formie.registerFormAssets(), craft.formie.renderFormAssets(), craft.formie.renderFormCss(), and craft.formie.renderFormJs(). Use craft.formie.formAssets().
Deprecated craft.formie.renderRuntimeAssets(), craft.formie.renderCss(), and craft.formie.renderJs(). Use craft.formie.frontendAssets().
Deprecated assets() as the form-scoped asset helper name. Use formAssets().
Deprecated legacy theme config root keys including radio, date, email, hidden, and phone. Use radioButtons, dateTime, emailAddress, hiddenField, and phoneNumber.
Deprecated legacy schema config keys including limitType, limitAmount, subfieldLabelPosition, includeInEmail, and emailValue.
Deprecated Integration::getFormSettingsHtml() for builder settings. Use Integration::defineFormSettingsSchema().
Deprecated custom integration front-end variable output via getFrontEndJsVariables(). Use IntegrationInterface::getClientModule().
Deprecated standalone Submissions::processPayments() usage. Payments now run through workflow tasks.
Deprecated selected submission dispatch pass-through methods on Submissions; use the canonical workflow, notification, integration, and payment services.
Deprecated runtime-named PHP classes in favor of client/frontend names where aliases are provided by Compatibility Mode.
Deprecated Rendering::EVENT_MODIFY_RUNTIME_JS_TRANSLATIONS, ModifyRuntimeJsTranslationsEvent, and getRuntimeJsTranslations() in favor of frontend-named equivalents.
Deprecated GraphQL page setting names enableJsEvents and jsGtmEventOptions.
Deprecated the refresh-token request form query parameter. Use handle.
Deprecated legacy Formie DOM events such as onFormieLoaded, onFormieInit, onFormieReady, onBeforeFormieSubmit, onFormieSubmit, onAfterFormieSubmit, onFormieSubmitError, onFormiePageToggle, onFormieValidate, and onAfterFormieValidate.
Deprecated legacy validator events such as formieValidatorInitialized, formieValidatorDestroyed, formieValidatorShowError, and formieValidatorClearError.
Deprecated the global Formie.refreshForCache() helper in favor of static-cache token refresh handling.
Removed
Remove the legacy CustomElement inheritance model from submissions.
Remove the FieldLegacy bridge trait.
Remove legacy Formie 3 field inputHtml() fallback behavior.
Remove expired Formie 3 field name helper compatibility surfaces.
Remove old sticky JavaScript form-bus APIs.
Remove the built-in Duplicate captcha integration.
Remove the built-in JavaScript captcha integration.
Remove the built-in Honeypot captcha integration.
Remove active support for file, Redis, and Memcached draft-state backends. Formie 4 supports the database-backed adapter.
Remove the old submissionStateMode and submissionStore settings from active configuration.
Remove enableGatsbyCompatibility from active configuration.
Remove active session/database branching for submission progression storage.
Remove getFrontEndJsVariables() as the custom integration front-end API.
Remove old built-in front-end bundle assumptions in favor of @verbb/formie-browser and the framework packages.
Remove direct templateHtml usage from the primary GraphQL form rendering path.
Remove Algolia as a built-in address provider module.