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, andModifyIntegrationFormSettingsSchemaEvent. - Add
Notifications::EVENT_MODIFY_NOTIFICATION_SCHEMAfor modifying notification schemas. - Add a new staged submission workflow service (
SubmissionWorkflow) withprepare,normalize,validate,screen,authorize,save,dispatch, andfinalizestages. - Add submission workflow process modes for normal submits, existing-submission edits, save-draft requests, and payment replays.
- Add submission workflow extension events:
EVENT_REGISTER_WORKFLOW_STAGES,EVENT_REGISTER_STAGE_TASKS,EVENT_BEFORE_STAGE,EVENT_AFTER_STAGE,EVENT_BEFORE_TASK, andEVENT_AFTER_TASK. - Add
SubmissionRequestEvent,SubmissionWorkflowStageEvent,SubmissionWorkflowTaskEvent,RegisterWorkflowStagesEvent, andRegisterStageTasksEvent. - Add workflow enums for stage and task names, including tasks such as
screen.runCaptchaChecks,save.processPayments,dispatch.sendNotifications, anddispatch.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, andmaxSavedDraftsPerSession. - Add anonymous client bootstrap and refresh rate-limit settings:
anonymousClientBootstrapRateLimit,anonymousClientRefreshRateLimit, andanonymousClientRateWindowSeconds. - Add static-cache token refresh handling with
staticCacheRefreshOnLoad. - Add
setOnlyCurrentPagePayloadfor limiting submitted multi-page payload handling to the current page. - Add
plainTextHtmlSanitizationModefor controlling plain-text HTML sanitization behavior. - Add
useCssLayersfor 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(), andField::getValueForReferenceBlock()as the canonical field reference value APIs. - Add
Field::defineValueForCondition()andSubmission::getFieldValueForCondition()for condition-specific value projection. - Add
Field::getCpEditHtml()as the canonical CP submission edit rendering contract. - Add
Field::defineFieldSlotTag()andSlotTagfor field slot tag customization. - Add
Form::EVENT_MODIFY_SLOT_TAG,Field::EVENT_MODIFY_SLOT_TAG, andIntegration::EVENT_MODIFY_SLOT_TAG. - Add
ModifyFormSlotTagEvent,ModifyFieldSlotTagEvent, andModifyIntegrationSlotTagEvent. - Add
Field::EVENT_MODIFY_VALUE_FOR_REFERENCEandField::EVENT_MODIFY_VALUE_FOR_REFERENCE_BLOCK. - Add
ValueContext::array(),ValueContext::reference(), andValueContext::referenceBlock(). - Add
craft.formie.parseValue()andcraft.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
FormTemplateoutput locations:PAGE_HEADER,PAGE_FOOTER,INSIDE_FORM, andMANUAL. - Add
initJsanduseObserverrendering 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, andServerRenderPayloadBuilder. - Add client request/response models including
FormSession,LoadContext,FormDefinition,FormBootstrap,SubmitRequest,PageTransitionRequest,SessionRefreshRequest, andSubmitResult. - Add client controllers for loading forms, changing pages, refreshing sessions, and submitting client-rendered forms.
- Add
FrontendAssetsas the canonical shared front-end asset service. - Add
ClientModule,ClientModuleContext, andRenderFramemodels. - Add
IntegrationInterface::getClientModule()for front-end module registration by integrations, captchas, address providers, and payments. - Add
ClientModulemanifests 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-corepackage for framework-agnostic form definitions, transports, field helpers, conditions, calculations, and client-rendered form state. - Add the
@verbb/formie-browserpackage as Formie’s canonical browser runtime for server-rendered forms. - Add the
@verbb/formie-reactpackage withFormieForm,FormieClientForm,useFormieHtml(),useFormieClient(),useFormie(),useFormieField(),useFormiePage(),useFormieInstance(), anduseFormieSlot(). - Add the
@verbb/formie-vuepackage with matching server-rendered and client-rendered Vue APIs. - Add the
@verbb/formie-web-componentspackage withformie-form,formie-core-form,registerFormieWebComponents(),FormieRegistry, andcreateFormieRegistry(). - Add REST and GraphQL transports for client-rendered forms.
- Add
createFormieClient(),formie(),FormieValidator,ModuleRegistry,defineCaptchaModule(),definePassiveCaptchaModule(),definePaymentModule(), anddefineAddressModule()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:readyevent. - Add page-level client analytics output via
data-formie-client-event. - Add GraphQL
formieHtmlFormfor server-rendered HTML form payloads. - Add GraphQL
formieClientFormfor 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-kitand@verbb/plugin-kit-reactas 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-domto@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:readytoformie:client:ready. - Move runtime/client PHP namespaces toward
clientnaming, while keeping selectedruntimeclass aliases in Compatibility Mode. - Rename runtime JS translation hooks to frontend JS translation hooks:
Rendering::EVENT_MODIFY_FRONTEND_JS_TRANSLATIONS,ModifyFrontendJsTranslationsEvent, andRendering::getFrontendJsTranslations(). - Replace
RuntimeModuleandRuntimeModuleContextterminology withClientModuleandClientModuleContext. - Replace
RuntimeRenderFrameterminology withRenderFrame. - Rename
RuntimeAssetstoFrontendAssets. - Replace
renderFormAssets(),registerFormAssets(),renderFormCss(), andrenderFormJs()withformAssets(). - Replace
renderRuntimeAssets(),renderCss(), andrenderJs()withfrontendAssets(). - Rename render options
renderCssandrenderJstoincludeCssandincludeJs. - Rename form template options
outputCssLayoutandoutputCssThemetooutputCss. - Rename form template options
outputJsBaseandoutputJsThemetooutputJs. - Change Formie’s default front-end CSS class prefix from
fuitoformie. - 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/submissionStateModechoice 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
submissionTitleFormatand 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
syncIdfan-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 toformieHtmlForm { html }. - Rename GraphQL page client event settings from
enableJsEventsandjsGtmEventOptionstoenableClientEventsandclientEventFields. - 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(), anddefineConditionsSchema()todefineFormBuilderGeneralSchema(),defineFormBuilderSettingsSchema(),defineFormBuilderAppearanceSchema(),defineFormBuilderAdvancedSchema(), anddefineFormBuilderConditionsSchema(). - Change schema node keys from
$formkitto$field. - Change schema help text keys from
helptoinstructions. - Change field builder previews from
getFormBuilderPreviewHtml()todefineFormBuilderPreviewSchema(). - Change field input template discovery from
getFrontEndInputTemplatePath()togetInputTemplatePath(). - Change field email template terminology from email templates to reference-block templates.
- Change field slot/tag customization from
HtmlTag/htmlTagterminology toSlotTag/slotTag. - Change form render IDs from
Form::getFormId()/setFormId()terminology toForm::getRenderId()/setRenderId(). - Move
Submissions::EVENT_BEFORE_SEND_NOTIFICATIONownership toNotifications::EVENT_BEFORE_SEND_NOTIFICATION. - Move
Submissions::EVENT_BEFORE_TRIGGER_INTEGRATIONownership toIntegrations::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 file upload validation, filename normalization, and safer CP/email summary URLs.
- 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()andForm::setFormId(). UseForm::getRenderId()andForm::setRenderId(). - Deprecated
Form::EVENT_MODIFY_HTML_TAG. UseForm::EVENT_MODIFY_SLOT_TAG. - Deprecated
ModifyFormHtmlTagEvent. UseModifyFormSlotTagEvent. - Deprecated
Field::EVENT_MODIFY_HTML_TAG. UseField::EVENT_MODIFY_SLOT_TAG. - Deprecated
ModifyFieldHtmlTagEvent. UseModifyFieldSlotTagEvent. - Deprecated
Field::EVENT_MODIFY_VALUE_AS_JSON. UseField::EVENT_MODIFY_VALUE_AS_ARRAY. - Deprecated
Field::EVENT_MODIFY_VALUE_FOR_EMAIL. UseField::EVENT_MODIFY_VALUE_FOR_REFERENCE_BLOCK. - Deprecated field value JSON methods such as
getValueAsJson()anddefineValueAsJson(). Use array-based equivalents. - Deprecated field variable value methods such as
getValueForVariable(),getValueForVariableRaw(),defineValueForVariable(), anddefineValueForVariableRaw(). Use reference value methods. - Deprecated field email value methods such as
getValueForEmail()anddefineValueForEmail(). Use reference-block value methods. - Deprecated field email template methods such as
getEmailTemplatePath(),getEmailHtml(),getEmailOptions(),hasEmailLabel(), andhasEmailPlaceholder(). Use reference-block equivalents. - Deprecated legacy field key helpers such as
getFieldKey(),getErrorKey(),getFullHandle(),getFullNamespace(), andgetReservedHandles(). - Deprecated legacy custom field schema methods in favor of
defineFormBuilder*Schema()methods. - Deprecated
getFormBuilderPreviewHtml()in favor ofdefineFormBuilderPreviewSchema(). - Deprecated
getFrontEndInputTemplatePath()in favor ofgetInputTemplatePath(). - Deprecated
defineHtmlTag()in favor ofdefineFieldSlotTag(). - Deprecated
Submission::getValueAsString(),Submission::getValueAsJson(),Submission::getValueForExport(), andSubmission::getValueForSummary()in favor ofgetFieldValue*()methods. - Deprecated
Submission::getFieldValueAsJson()in favor ofSubmission::getFieldValueAsArray(). - Deprecated
Submission::getValuesAsJson()in favor ofSubmission::getValuesAsArray(). - Deprecated
Submission::getFieldValueForEmail()in favor ofSubmission::getFieldValueForReferenceBlock(). - Deprecated
Submission::getFieldValueForVariable()in favor ofSubmission::getFieldValueForReference(). - Deprecated
SubmissionContentManager::getValuesAsJson()in favor ofgetValuesAsArray(). - Deprecated
ValueContext::json()andValueContext::TYPE_JSON. UseValueContext::array()andValueContext::TYPE_ARRAY. - Deprecated
ValueContext::variable()andValueContext::TYPE_VARIABLE. UseValueContext::reference()andValueContext::TYPE_REFERENCE. - Deprecated
ValueContext::email()andValueContext::TYPE_EMAIL. UseValueContext::referenceBlock()andValueContext::TYPE_REFERENCE_BLOCK. - Deprecated
craft.formie.registerAssets(),craft.formie.registerFormAssets(),craft.formie.renderFormAssets(),craft.formie.renderFormCss(), andcraft.formie.renderFormJs(). Usecraft.formie.formAssets(). - Deprecated
craft.formie.renderRuntimeAssets(),craft.formie.renderCss(), andcraft.formie.renderJs(). Usecraft.formie.frontendAssets(). - Deprecated render option keys
renderCss,renderJs,outputCssLayout,outputCssTheme,outputJsBase, andoutputJsTheme. - Deprecated
assets()as the form-scoped asset helper name. UseformAssets(). - Deprecated legacy theme config root keys including
radio,date,email,hidden, andphone. UseradioButtons,dateTime,emailAddress,hiddenField, andphoneNumber. - Deprecated legacy schema config keys including
limitType,limitAmount,subfieldLabelPosition,includeInEmail, andemailValue. - Deprecated
Integration::getFormSettingsHtml()for builder settings. UseIntegration::defineFormSettingsSchema(). - Deprecated custom integration front-end variable output via
getFrontEndJsVariables(). UseIntegrationInterface::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, andgetRuntimeJsTranslations()in favor of frontend-named equivalents. - Deprecated GraphQL page setting names
enableJsEventsandjsGtmEventOptions. - Deprecated the refresh-token request
formquery parameter. Usehandle. - Deprecated legacy Formie DOM events such as
onFormieLoaded,onFormieInit,onFormieReady,onBeforeFormieSubmit,onFormieSubmit,onAfterFormieSubmit,onFormieSubmitError,onFormiePageToggle,onFormieValidate, andonAfterFormieValidate. - Deprecated legacy validator events such as
formieValidatorInitialized,formieValidatorDestroyed,formieValidatorShowError, andformieValidatorClearError. - Deprecated the global
Formie.refreshForCache()helper in favor of static-cache token refresh handling.
Removed
- Remove the legacy
CustomElementinheritance model from submissions. - Remove the
FieldLegacybridge trait. - Remove legacy Formie 3 field
inputHtml()fallback behavior. - Remove expired Formie 3 field
namehelper 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
submissionStateModeandsubmissionStoresettings from active configuration. - Remove
enableGatsbyCompatibilityfrom 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-browserand the framework packages. - Remove direct
templateHtmlusage from the primary GraphQL form rendering path. - Remove Algolia as a built-in address provider module.