FormBus
FormBus is what you are looking for if you do server-side form validation, and you want a plug and play front-end solution to do the typical.
You can use the built-in directives to show or toggle CSS class names when the fields validation failed, or when the submission was successful, or something went wrong.
In the WordPress context, FormBus is suitable when you are using a forms plugin and:
- The generated HTML structure does not suit your needs, or you are using utility-first CSS frameworks like Tailwind CSS, and you wish to use those class names
- You are deep into the rabbit hole of front-end optimization, and you don't want any bloated libraries or dependencies that you are not using anywhere else, like jQuery
- You are using WordPress as a headless CMS, and you are using the REST API as a primary way to interact with it
Check out the video demonstration
Usage
Installation
The recommended way of installing FormBus is using npm:
npm install formbus
form
Submitting your As long as your form
element is set up correctly:
-
action
is pointing to the API endpoint -
method
is set to topost
- input elements have the
name
attribute
FormBus is able to construct the request and send it. It uses Fetch API
, and the data is constructed using FormData
.
If you need to set additional configuration values, for example, headers, you can use the configuration object. It's explained later in the documentation.
<form action="https://your-website.com/wp-json/contact-form-7/v1/contact-forms/<ID>/feedback"
method="post"
id="contact-form">
<div class="form-group">
<label for="name">Your Name</label>
<input type="text" name="your-name" class="form-control" id="name">
</div>
<!-- Other input elements -->
<button type="submit" class="btn btn-primary">Submit</button>
</form>
In your JavaScript file, import the corresponding function for the service.
The first argument should be a CSS selector matching the form
element or a parent, wrapper element.
The selector expects a single element; if multiple are matched, only the first one is used.
import { contactForm7Bus } from 'formbus';
const contactFormBus = contactForm7Bus('form#contact-form');
Or you can pass a HTMLElement
directly:
const contactFormWrapper = document.querySelector('section#contact-form-section');
const contactFormBus = contactForm7Bus(contactFormWrapper);
You have to call the init
method explicitly for the initialization:
contactFormBus.init();
Later on, you can call destroy
if you want to remove the events attached to the form:
contactFormBus.destroy();
form
elements
With multiple If you want to target multiple elements on the page, first get the elements, and then loop over them:
const forms = document.querySelectorAll('form');
forms.forEach(form => {
const cf7FormBus = contactForm7Bus(form);
cf7FormBus.init();
});
Supported services
Contact Form 7
Just another contact form plugin for WordPress. Simple but flexible.
import { contactForm7Bus } from 'formbus';
The REST API endpoint, if not altered, should look like this:
https://your-website.com/wp-json/contact-form-7/v1/contact-forms/<ID>/feedback
Gravity Forms
Gravity Forms is the Easiest, Most Trusted Tool to Create Advanced Forms for Your WordPress-Powered Website.
import { gravityFormsBus } from 'formbus';
The REST API endpoint, if not altered, should look like this:
https://your-website.com/wp-json/gf/v2/forms/<ID>/submissions
Your service
FormBus is extensible; if your endpoint returns field validation errors, and you can infer the submission state, you should be able to use it with your service. More about this later.
Directives
Directives are useful when you want to have what is expected. Just add one of the attributes to an element, and FormBus will do the rest.
<form action="https://your-website.com/wp-json/contact-form-7/v1/contact-forms/43/feedback"
method="post"
id="contact-form"
+ form-state-class>
+ <div form-state-message></div>
+ <div class="form-group" field-validation-error-class="your-name">
<label for="name">Your Name</label>
<input type="text" name="your-name" class="form-control" id="name">
+ <div field-validation-error-message="your-name"></div>
</div>
<!-- Other input elements -->
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Depending on your case, you can use only one directive or all of them:
field-validation-error-class
field-validation-error-message
form-state-class
form-state-message
For separate form states:
form-submission-error-class
form-submission-error-message
form-submission-success-class
form-submission-success-class
form-validation-error-class
form-validation-error-message
Events
With the helper functions, you get a lot of flexibility, but it's up to you to act on different states.
Events are attached to the form
element.
afterFormBusResponse
const contactForm = document.querySelector('#contact-form');
const contactFormBus = contactForm7Bus(contactForm);
contactFormBus.init();
contactForm.addEventListener('afterFormBusResponse', ({ detail: response }) => {
console.log(response);
});
This custom event is fired after the form submission when a response is returned.
The event's detail contains the raw response object. The format and the returned data that depends on the service.
Response helper functions
Because the response differs from service to service, FormBus provides a set of helper functions that you can use instead of writing logic that is bound to a specific service.
The following methods are accessible under the responseHelpers
key:
getFieldValidationErrorMessage(responseData, fieldName)
getFormSubmissionErrorMessage(responseData)
getFormSubmissionSuccessMessage(responseData)
getFormValidationErrorMessage(responseData)
isFieldValidationError(responseData, fieldName)
isFormSubmissionError(responseData)
isFormSubmissionSuccess(responseData)
isFormValidationError(responseData)
Here's an example where it replaces the form
element with the success message:
contactForm.addEventListener('afterFormBusResponse', ({ detail: response }) => {
const helpers = contactFormBus.responseHelpers;
if (!helpers.isFormSubmissionSuccess(response)) {
alert('Something went wrong.');
return;
}
const successMessage = helpers.getFormSubmissionSuccessMessage(response);
contactFormBus.destroy();
contactForm.innerHTML = `<p>${successMessage}</p>`;
});
beforeFormBusRequest
contactForm.addEventListener('beforeFormBusRequest', ({ detail: formData }) => {
console.log(formData);
});
The custom event's detail contains the FormData
that is sent with the request.
Configuration
You can overwrite the default configuration by passing an object as the second argument.
const yourConfig = {
classNames: {
fieldValidationError: '--is-error'
}
};
const contactFormBus = contactForm7Bus('#contact-form', yourConfig);
Configuration values are merged with the defaults. If you want to overwrite a few of them, you don't have to provide the entire configuration object.
The default configuration:
const defaultConfig = {
directives: {
fieldValidationErrorClassNames: 'field-validation-error-class',
fieldValidationErrorMessage: 'field-validation-error-message',
formStateClassNames: 'form-state-class',
formStateMessage: 'form-state-message',
formSubmissionErrorClassNames: 'form-submission-error-class',
formSubmissionErrorMessage: 'form-submission-error-message',
formSubmissionSuccessClassNames: 'form-submission-success-class',
formSubmissionSuccessMessage: 'form-submission-success-message',
formValidationErrorClassNames: 'form-validation-error-class',
formValidationErrorMessage: 'form-validation-error-message'
},
classNames: {
fieldValidationError: 'is-error is-field-validation-error',
formSubmissionError: 'is-error is-form-submission-error',
formSubmissionSuccess: 'is-success is-form-submission-success',
formValidationError: 'is-error is-form-validation-error'
},
request: {}
};
Customizing the directive attributes
const yourConfig = {
directives: {
fieldValidationErrorClassNames: 'data-field-error-class',
fieldValidationErrorMessage: 'data-field-error-message'
}
};
<form action="https://your-website.com/wp-json/contact-form-7/v1/contact-forms/43/feedback"
method="post"
id="contact-form"
form-state-class>
<div form-state-message></div>
- <div class="form-group" field-validation-error-class="your-name">
+ <div class="form-group" data-field-error-class="your-name">
<label for="name">Your Name</label>
<input type="text" name="your-name" class="form-control" id="name">
- <div field-validation-error-message="your-name"></div>
+ <div data-field-error-message="your-name"></div>
</div>
<!-- Other input elements -->
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Use your service
Instead of service functions, use the formBus
that expects to receive response helpers' implementation as the second argument:
import { formBus } from 'formbus';
const contactFormBus = formBus('#contact-form', serviceResponseHelpers);
contactFormBus.init();
You are expected to return a string
or a null
for these functions:
getFieldValidationErrorMessage
getFormSubmissionErrorMessage
getFormSubmissionSuccessMessage
getFormValidationErrorMessage
You are expected to return a boolean
for the following:
isFieldValidationError
isFormSubmissionError
isFormSubmissionSuccess
isFormValidationError
const getFieldValidationErrorMessage = (response, fieldName) => {
return null;
};
const getFormSubmissionErrorMessage = (response) => {
return null;
};
const getFormSubmissionSuccessMessage = (response) => {
return null;
};
const getFormValidationErrorMessage = (response) => {
return null;
};
const isFieldValidationError = (response, fieldName) => {
return false;
};
const isFormSubmissionError = (response) => {
return false;
};
const isFormSubmissionSuccess = (response) => {
return false;
};
const isFormValidationError = (response) => {
return false;
};
const serviceResponseHelpers = {
getFieldValidationErrorMessage,
getFormSubmissionErrorMessage,
getFormSubmissionSuccessMessage,
getFormValidationErrorMessage,
isFieldValidationError,
isFormSubmissionError,
isFormSubmissionSuccess,
isFormValidationError
};
The configuration object can be passed as the third argument.
const contactFormBus = formBus('#contact-form', serviceResponseHelpers, yourConfig);
Changelog
All notable changes to FormBus are documented in CHANGELOG.md.
Contributing
If you are using FormBus and found a bug, then you are likely the most capable of fixing it. You can contribute back the fix by submitting a pull request together with the steps to reproduce it.
Another way to help is by improving the readme.