Formie 3

Verbb Team Verbb Team Aug 2024 10 min read

We've been hard at work with Formie 3 for Craft 5 with some bigger than usual changes, including exciting new features, and internal improvements. The latter of which paves the way for the future growth of Formie, which we're pretty excited about! It's probably the biggest re-architecturing of Formie we've done.

If you want to jump straight into what you need to do, check out our comprehensive upgrade guide for everything that's changed.

What's Changed?#

First and foremost, Formie 3 is for Craft 5 — which means a few behind-the-scenes changes to make things compatible with the latest Craft release. For the most part, all changes are pretty internal to Formie itself and its architecture.

A big theme for Formie 3 is control. Putting more of the responsibility for things in our hands, and less reliance on third-party code. This has been particularly important as Formie grows, to ensure the stability of changes isn't affecting our customers with something as business-critical as forms.

We've strived to ensure any breaking changes are minimal unless absolutely required, and major changes marked as deprecated to ease the transition to Formie 3.

Content Tables#

This is purely informational, in case you want to know how content is stored.

Formie 2 stored all submission content in dedicated tables — much like how content was stored for Craft elements. Craft 5 has moved all content for elements into a single JSON column in the database, bringing many improvements. Formie has followed suit — there's no more fmc_* content tables, it's all against a Submission in formie_submissions.

This not only means better performance for submissions but addresses a long-standing issue of being limited to a certain number of fields in a form. With this change, we're very pleased to announce your forms can now contain an unlimited number of fields. First to show us a form with 5,000 fields gets a prize.

Repeater & Group Fields#

If you deal with Repeater and Group fields in any way with custom templating, custom validators, accessing field content or other means, read the upgrade guide.

Repeater and Group fields have been radically improved behind the scenes. Previously, these were functionality the same as a Super Table and Static Super Table field respectively. These were a massive performance issue for complex forms, and dealing with content in these fields was needlessly complex.

So - these fields still work the same, but their underlying structure is now a simple array, ditching the complexities of elements. This means easier-to-deal with fields, and faster Forms and Submissions.

Fields#

If you have created your own custom fields, read the upgrade guide.

Fields themselves have also had a big makeover behind the scenes! We previously extended Craft's own Field classes (for the custom fields used in the control panel), but in practice, this has caused us plenty of support issues and needless breaking changes. Formie's usage of fields was starting to outgrow what benefits we were once getting from Craft.

Formie 3 now controls all functionality regarding fields and field layouts itself. This means all functionality is purpose-driven to Formie's use-case and not concerned with other functionality Craft uses with its own fields.

It's one of the major points in addressing scalability in Formie's future. But right now, you should find fields are far more performant than in Formie 2.

Front-end Validation#

If you have registered your own custom front-end validators, read the upgrade guide.

We previously used bouncer.js (opens new window) for front-end JavaScript validation. It's since proved pretty limiting in how validation is handled and is no longer being maintained. We tossed up other (opens new window) options, but didn't want to fall into the same trap. We also wanted to tailor the developer experience to Craft and Formie.

So — we built our own JavaScript validation framework which easily handles translations, custom validators and lots more. It's much more streamlined compared to anything off the shelf, ensuring a smaller JavaScript payload size for end-users.

Best of all, it gives us more control over the entire validation experience, rather than trying to bend another tool to our will.

For example, take a look at how a custom validation rule is set in Formie 2:

import { t } from 'vendor/formie/frontend/utils/utils';

let $form = document.querySelector('#formie-form-1');

function customRule() {
    return {
        minLength(field) {
            const limit = field.getAttribute('data-limit');

            // Don't trigger this validation unless there's the `data-limit` attribute
            if (!limit) {
                return false;
            }

            return !(field.value.length > limit);
        },
    };
}

function customMessage() {
    return {
        minLength(field) {
            return t('The value entered must be at least {limit} characters long.', {
                limit: field.getAttribute('data-limit'),
            });
        },
    };
}

$form.addEventListener('registerFormieValidation', (e) => {
    e.preventDefault();

    // Add our custom validations logic and methods
    e.detail.validatorSettings.customValidations = {
        ...e.detail.validatorSettings.customValidations,
        ...this.customRule(),
    };

    // Add our custom messages
    e.detail.validatorSettings.messages = {
        ...e.detail.validatorSettings.messages,
        ...this.customMessage(),
    };

    // ...
});

That's a fair bit of code we think! There's also lack of translation support which can be tedious to sort out in your own code. The same code can be implemented in Formie 3:

let $form = document.querySelector('#formie-form-1');

$form.addEventListener('onFormieThemeReady', (event) => {
    event.detail.addValidator('minLength', ({ input }) => {
        const limit = input.getAttribute('data-limit');

        // Don't trigger this validation unless there's the `data-limit` attribute
        if (!limit) {
            return true;
        }

        return input.value.length > limit;
    }, ({ label, input, t }) => {
        const limit = input.getAttribute('data-limit');

        return t('The value entered in {label} must be at least {limit} characters long.', { label, limit });
    });
});

The result is a far more leaner, modern and flexible approach to validators.

OAuth Integrations#

If you have created your own custom integration with OAuth, read the upgrade guide.

OAuth-based integrations now use the Auth Module to handle authentication under the hood. This greatly simplifies our codebase and doesn't reinvent the wheel for something like connecting to a third-party provider.

Formie takes care of migrating you over to the Auth Module so you shouldn't notice any change in behaviour unless you've implemented your own custom integration that uses OAuth.

Proper "All Submissions" View#

Submissions now show incomplete and spam submissions alongside completed submissions in a single view. This aligns more with Craft's own handling of draft elements (think Entry drafts) and helps to identify both false-positive spam and abandoned submissions in a single view.

This is of course configurable in case you prefer to retain the old behaviour.

A spam, incomplete and complete submission walk into a bar...

What's New?#

That covers the major changes in Formie 3, but there's also a bunch of brand-new features.

Front-end Performance#

By default, Formie requires some JavaScript to help with all the front-end goodness it offers, from field functionality to improving UX to captchas. However, rather than running this JavaScript immediately, we figure it's best to only initialize forms when they're going to be used.

For example, a common scenario is to have a form in a modal dialog. You might be rendering the form with Twig, but using a method to hide it until a user opens the modal. Formie will initialize the hidden form, which is wasted execution time if the user never opens the modal.

Similarly, any captchas should behave the same way. If a form uses reCAPTCHA, it shouldn't load until the captcha is actually shown, saving page load speed requests.

We're happy to say in Formie 3 both of these are handled, as Formie has more smarts about when to initialize JavaScript. This greatly improves the overall page speed when Formie forms are used.

Sub-Fields#

Address, Date, Name and Phone are all considered "sub-fields" as they act as containers for fields within them. Similar to Nested Fields like Group or Repeater — but instead of being able to drop any field and configure it, Sub-Fields' inner fields are set.

Formie 3 has made configuring these inner fields possible exactly like regular fields. While you can't remove Sub-Fields' inner fields, you can enable/disable, re-order, rename and configure as needed. You can even control the row/column layout of Sub-Fields.

The new sub-field configuration is a mini form builder in itself!

Name fields are conditionally Sub-Fields, and Phone fields are no longer Sub-Fields in Formie 3.

Sub-Field fields are just like regular fields.

More Permissions#

To give restricted content editors more options, we've added a bunch of user permissions for Forms and Submissions.

  • Access forms
    • Create forms
    • Delete forms
    • Manage all forms
      • Show form appearance tab
      • Show form behaviour tab
      • Show form email notifications tab
        • Show email notification advanced tab
        • Show email notification templates tab
      • Show form integrations tab
      • Show form usage tab
      • Show form settings tab
  • Access submissions
    • View all submissions
      • Create submissions
      • Save submissions
      • Delete submissions
  • Access sent notifications
    • View all sent notifications
      • Resend sent notifications
      • Delete sent notifications

Better Keyboard Support#

While there's still work to be done on full accessibility, we've improved a lot of keyboard accessibility for the form builder. Notably, hitting return when editing a field actually submits the modal window for example.

Variable Picker Helper#

Being able to pick fields and other global variables is a great aspect of Formie. We've given it a little love by including a dropdown suggestion box when typing in the field of any options available that match the typed characters.

Pick variables like a power user as you type.

Just start with a { and you'll be a variable-picking power user before you know it.

Required Field Indicator#

While using an asterisk * is a pretty standard UX pattern to denote a required field, we've added in options to configure this. Maybe you want all fields required by default, and only state what's optional (another popular UX pattern).

Switch the required field indicator for fields.

Modify Page Settings in Templates#

As the heading says, change the settings of a page, including the buttons!

{% set form = craft.formie.forms.handle('contactForm').one() %}

{% do form.setPageSettings('page-1', {
    {# Override the submit button text for "Page 1" #}
    submitButtonLabel: 'Click here to submit',
}) %}

{{ craft.formie.renderForm(form) }}

Integration Performance#

For integrations with a lot of different data properties, we now only fetch the enabled ones. For example, Salesforce supports mapping to a Contact, Lead, Opportunity, Account, or Case — but it's rare to need all of them. The integration mapping component was limited to fetching fields and settings for all these data objects whether they were enabled or not.

Not in Formie 3 — now only enabled data objects are fetched from APIs.

Pick Label or Value#

For options fields (Dropdown, Checkboxes, Radio Buttons) you have the option to pick whether to use the option label or value when used in Email Notifications. Previously Formie assumed you wanted to use the value of the option, which wasn't always the case. Formie also now defaults to using the option label.

Similarly, for Element fields (Entries, Categories, etc) you have the option to pick whether to use the front-end URL or the control panel URL to the element.

Move Fields in Groups#

A neat little feature made possible thanks to simplifying Group fields — you can now move fields in and out of Group fields. This will also shift any content associated with these fields.

You can now also add Group fields from other forms as "existing fields" just like all other fields.

Email Notifications on Status Change#

A pretty common scenario is to have submissions come through as one status ("Pending") for an editor to moderate and action. They might then like to assign another status which should trigger an Email Notification to send to a particular party.

Setting this up via conditions is now possible, and whenever the status change for a Submission is met for the Email Notification conditions, the email is sent.

Stripe Payments#

We've also updated the Stripe payment integration to allow for more than just credit card payments. Stripe now supports the full spectrum of payment options from Apple Pay, Google Pay, Klarna, PayPal and lots more (depending on your country).

Get paid in more ways with Stripe Payments.

The Future#

All of the above work is gearing Formie towards some major new features we've been planning, such as surveys, quizzes and proper multi-site support, which we've been working towards since Formie was first introduced. We're not there yet, but these internal improvements are the first steps in the right direction.

Coming up next though will be a 2.2 (opens new window) release for Craft 4 (and 3.1 for Craft 5) with a focus on new integrations and features.

As we've mentioned, Formie 1 for Craft 3 has reached its end of life, but we'll continue adding new features and full support for Formie 2 for Craft 4.

Get To It!#

Formie 3 has been in beta for a few months as we've stabilised these large changes. A massive thanks to all the beta testers out there who have helped shape the plugin. We're stoked to see where Formie can go from here.

Formie 3 is available today for Craft 5 on the plugin store (opens new window).