Form-building is tedious
Show of hands: When you’re building a web application, what’s your favorite part of the process? Did you say “implementing the forms”? No one ever does.
Forms are essential yet painful. User experience expectations are high, but since we’re always starting with primitive HTML elements (even when using React or Vue), it requires a lot of effort to build high-quality forms. The developer experience is marred with inconsistent input tags, poor frontend validation, accessibility requirements, and lots of tedious markup, just to name a few frustrations.
What if we standardized the API for all inputs so that each input type was predictable and even interchangeable? What if we had access to an expressive syntax for executing complex frontend validation? What if we super-charged
v-model so that it could be applied once to an entire
form element to generate a single object from our form data?
What if we learned from Vue — built an easy-to-understand API that didn’t restrict power users — and focused our energy on reinventing the form-authoring experience? Developers would be a heck of a lot happier, and we’d all save a ton of time. These quality-of-life improvements, and many others, are available with Vue Formulate. Let’s take a look.
A simple example
Let’s start with a simple example doing things the traditional Vue way we’re familiar with. Below is a mock user sign-up form for a (fake) conference. In this example, we’re asking for a username, email, short bio, password, and password confirmation.
This is a simple form, but already there’s a number of headaches we’ve had to deal with when authoring it:
- The APIs for inputs are not 100 percent consistent, and
textareais its own discrete tag differing from everything else
- Each input requires a label for accessibility, and some inputs need help text to facilitate good UX. This results in a verbose amount of markup
- We’re able to get basic (and ugly) validation for required fields, the username formatting, the email address formatting, and the password length, but we’re going to need to roll our own validation if we want to check the password confirmation (which we do)
- We’re on our own if we want to provide a friendly check for the user to see if their chosen username is available before they submit the form
Let’s add in the password confirmation validation and stub out the username availability check from the above list. After all, our users are going to expect nice UX behaviors, and we’re not going to ship this form without them — right?
Once again, we’ll use the same vanilla Vue approach we’re already familiar with. After a bit more work, we end up with something that looks like this:
The user experience on the form is nicer, but our simple example is starting to look… complicated. Note the addition of several
ref attributes to help us track input values in our component as well as
blur event handlers for triggering our own custom validation methods. These work well enough, but in the case of the username check, it’s possible to quickly submit the form with an invalid username due to the async nature of the availability check.
Our component now contains all of this complexity — in an admittedly imperfect state — and this is for a form with only five inputs! On top of that, all the logic we’ve written in our component is bound to this particular form and is not easily reusable. Reuse will require us to do additional work to abstract our validation functionality away into a utility library somewhere in our project or, worse, just copy/paste and modify it whenever we author another form that requires similar behaviors.
We should do better. We can do better. Let’s take look at the same form written with Vue Formulate.
Ah! Much nicer. All of the same functionality we had hand-rolled (and more), the template is cleaner (our component’s template code was cut in half), and our component contains less one-off logic. There are some key items to address in the above demo:
- There are only two distinct components we need to worry about:
FormulateInput. That’s it!
- The APIs for the inputs are all internally consistent
- For the username, email, and password fields, we are able to use expressive inline validation rules to perform complex validation logic without adding any one-off methods or computed properties to our component
- The validation rules we’ve applied output human-friendly inline error messages without any manual configuration on our part
- By using the
^prefix on validation rules, we can tell Vue Formulate to “bail” on validation if that particular rule fails, limiting the number of errors shown at one time
- For the username check, we’re able to declare our own custom validation rule that performs an async check against known usernames (mocked with a local data prop in this example). We’re also able to supply a custom validation message that should display if the rule fails
Not only is the code concise and easier to understand at a glance, Vue Formulate is providing us with some great UX features for free. Validation rules produce well-formatted error messages, the form itself will not submit until all validation rules (including async rules) have passed, and labels and help text exist as props on
FormulateInput, allowing for the same improved UX our users expect without requiring bloated markup to be written in our template.
All of this and we’re only scratching the surface of Vue Formulate’s features.
Let’s make something complicated
We’re going to build a multi-attendee purchase form for a (fake) conference (FormulateConf 2020) and use it as an opportunity to showcase some of Vue Formulate’s more powerful features.
To start, we’ll scaffold out our form’s functionality for a single attendee, with inputs to capture a name, email, ticket tier, and preferred payment method. We’ll add Vue Formulate validation, labels, and help text since we’re now familiar with them.
This is great! We would be ready to roll if we only needed our form to account for a single user at a time. Instead, we want to allow a user (for example, an office manager) to book tickets for multiple attendees and submit the form as a single payment. This is a perfect use case for Vue Formulate’s repeatable grouped fields.
Let’s do a minimal amount of refactoring to take advantage of repeatable groups.
Huzzah! By wrapping our user detail fields in a
FormulateInput of type
group and setting the
repeatable prop to
true, we’re able to implement repeatable fields out of the box. That was too easy! We’ve also added a
v-model attribute to the group and revised our
total computed property to sum up the one-or-many tickets represented in our form data. Pretty neat, huh?
In Vue Formulate,
v-model is powerful and works exactly how you hope it would. You can model more than just single inputs or grouped fields. Let’s slap a
v-model on the root
FormulateForm element itself. We’ll output its value onto the page so that we can see the data structure provided by Vue Formulate as we interact with the form.
And that’s that! While the functionality we’ve created is complex, what we are left with is a component that is refreshingly easy to read and requires minimal custom logic to power its experience.
Oh, the things you’ll do!
Vue Formulate dramatically reduces the complexity involved in writing forms with Vue. We’ve covered a lot of ground in this introduction, but there’s plenty more to explore. With Vue Formulate you can also:
- Easily handle and populate form errors you receive from a backend API
- Repopulate a form from a single object, useful for setting initial state on things such as editable user profiles
- Override any of the default Vue Formulate component templates with full scoped slot support
- Generate a form from a JSON object thanks to the standardized API on the single
Vue Formulate is — and always will be — free and open source. Our comprehensive developer documentation will help you integrate Vue Formulate into your next project. Bonus: because it’s <15KB gzipped, you don’t even need to feel guilty about it. Add Vue Formulate to your project and go build something awesome!
Experience your Vue apps exactly how a user doesDebugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket. https://logrocket.com/signup/
The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.
Modernize how you debug your Vue apps - Start monitoring for free.