Introducing Vue Formulate — truly delightful form authoring.
Tags: vue, forms, webdev, javascript
Published: 2020-05-19 19:38:53

[Vue Formulate](https://vueformulate.com/) has been in the wild for 2 months now, and with the latest release (v2.3) the project has enough momentum to warrant a post from its creator (me, [Justin Schroeder](https://twitter.com/jpschroeder)) on why it exists, what it does, and where it is going.

![Quick example of Vue Formulate](https://assets.wearebraid.com/vue-formulate/formulate-simple.gif)

### The problem with forms

When you’re learning to program, one of the most exciting early progressions is when you make your "Hello World" app _interactive_ by prompting a user for their name. Take those mad I.O. skills to the web and it gets even easier! Just plop an `<input>` tag into your markup and you’re off the races right? Well...not so fast. 

Over the past two months, I've gotten a lot of questions about Vue Formulate. Unsurprisingly one of the most frequent ones is, "What’s wrong with HTML?".

{% twitter 1236275673108557824 %}

There’s nothing _wrong_ with HTML, of course, just like there was nothing wrong with JavaScript before Vue and React (I know, I know, Vanilla purists’ blood is boiling out there). HTML, React, Vue... it doesn’t matter — the reality is: creating high-quality forms requires a lot of consideration. Labels, help text, validation, inline file uploads, and accessibility are just a few of the items a developer will need to address. This almost inevitably amounts to gobs of copy/paste and boilerplate markup littered throughout your codebase.

There are other issues too. HTML validation, for example, is pretty limited. What if you want to asynchronously check if a username is already taken? What if you want to have well-styled validation errors? What if you want to offer the ability for someone to add more attendees on their ticket purchase? None of these are available to native HTML/React/Vue without considerable effort. Furthermore, maintaining a high level of quality while working on such disparate features becomes secondary to just making the form _work_. This is fertile ground for a library to help increase developer happiness while pushing quality and accessibility.

### Why is Vue Formulate different?

Vue Formulate is far from the first library to address these concerns. Our long-time friends in the community have been fighting these battles for ages: vue-forms, VeeValidate, Vuelidate, and even some UI frameworks like Vuetify aim to help developers author better forms. These are great packages and I wouldn’t discourage you from using them if they’re appropriate for your project. However, Vue Formulate approaches the same problems with two specific objectives:

1. Improve the developer experience of form authoring.
2. Increase the quality of forms for end-users.

In order to provide a great developer experience, Vue Formulate needs to focus on being a _comprehensive form authoring_ solution. It cannot just be a validator and doesn’t aspire to become a full UI library. Instead, these guiding principles have resulted in a highly consistent component-first API focused solely on first-class form authoring. To that end, every single input in Vue Formulate is authored with the same component `<FormulateInput>`, smoothing out the inconsistencies in HTML’s default elements such as `<input>`, `<textarea>`, `<select>` and others. In Vue Formulate you simply tell the `<FormulateInput>` what type of input it should be — a text input (`<FormulateInput type="text">`) and a select input (`<FormulateInput type="select">`) can even be dynamically exchanged by changing the `type` prop on the fly.

Why is this better you ask? It’s better because it’s easy to remember, fast to compose, and reduces mistakes. We absolutely shouldn’t discount those very real quality of life improvements... but of course that’s not all.

By ensuring all inputs conform to a single component interface we allow for more powerful enhancements like automatic labels, declarative validation, form generation, automatic accessibility attributes, and support for complex custom inputs. This allows a `FormulateInput` component to maintain an easy-to-use API while being endowed with super powers. Consider how similarly these two inputs are authored using Vue Formulate and yet how different their actual HTML implementation is:

```vue
<FormulateInput
  type="email"
  name="email"
  label="Enter your email address"
  help="We’ll send you an email when your ice cream is ready"
  validation="required|email"
/>
<FormulateInput
  type="checkbox"
  name="flavor"
  label="Pick your 2 favorite flavors"
  validation="min:2,length"
  :options="{
   vanilla: 'Vanilla',
   chocolate: 'Chocolate',
   strawberry: ’Strawberry',
   apple: 'Apple'
  }"
/>
```

{% codepen https://codepen.io/justin-schroeder/pen/dyYQZgr %}

Now, notice some of the things we _didn’t_ have to deal with in that example:

- `<label>` elements inputs were automatically generated and linked to the `<input>` element via auto-generated ids (specify if you want).
- Help text was generated in the proper location and the input was linked to it with `aria-describedby`.
- We added real time input validation without having to explicitly output errors.
- Multiple checkboxes were rendered with their values linked together.
- The labels for the checkboxes automatically adjusted their position.

By consolidating inputs into a single `FormulateInput` component, we drastically improve the quality of life for developers, and simultaneously create a powerful hook for adding new features and functionality to those inputs. As a bonus, when it comes time to upgrade to Vue 3’s Composition API, Vue Formulate’s component-first API means developers won’t need to refactor anything in their template code.

### Neato, but where’s my form?

I’ve explained Vue Formulate’s purpose and its unique approach to inputs, but how about the form itself? Let’s consider the purpose of the native `<form>` element: to transmit input from a user to a server by aggregating the values of its input elements. What does that look like in Vue Formulate? Pretty much exactly what you would expect:

```vue
<template>
  <FormulateForm
    @submit="login"
  >
    <FormulateInput
      type="email"
      name="email"
      label="Email address"
      validation="required|email"
    />
    <FormulateInput
      type="password"
      name="password"
      label="Password"
      validation="required" 
    />
    <FormulateInput label="Login" type="submit" />
  </FormulateForm>
</template>

<script>
export default {
  methods: {
    login (data) {
      /* do something with data when it passes validation:
       * { email: 'zzz@zzz.com', password: 'xyz' }
       */
      alert('Logged in')
    }
  }
}
</script>
```

Great, so data aggregation works just like a normal form, but there’s not anything “reactive” here yet. Ahh, let’s slap a `v-model` onto that form — and — presto! We have a fully reactive object with all the data in our form.

```vue
<template>
  <FormulateForm
    @submit="login"
    v-model="values"
  >
    <FormulateInput
      type="email"
      name="email"
      label="Email address"
      validation="required|email"
    />
    <FormulateInput
      type="password"
      name="password"
      label="Password"
      validation="required" 
    />
    <FormulateInput label="Login" type="submit" />
    <pre>{{ values }}</pre>
  </FormulateForm>
</template>

<script>
export default {
  data () {
   return {
     values: {}
   }
  },
  methods: {
    login (data) {
      /* do something with data:
       * { email: 'zzz@zzz.com', password: 'xyz' }
       */
      alert('Logged in')
    }
  }
}
</script>
```

{% codepen https://codepen.io/justin-schroeder/pen/VwvVyZo %}

And yes, `v-model` means its _two-way_ data binding. You can write values into any input in your form by changing properties on a single object. Aim small, miss small — so let’s shoot for making “it just works” the default developer experience.

{% codepen https://codepen.io/justin-schroeder/pen/xxwQymd %}

### Slots, custom inputs, plugins — oh my!

This article is just an introduction — not a substitute for the full documentation — but it wouldn’t be fair to leave out some of my favorite extensibility features. Form authoring tools need to be flexible — there’s an edge case for everything right? Vue Formulate’s highly opinionated component-first API may seem at odds with flexibility, but in reality that consistent API is the core behind a highly flexible architecture.

Slots are a great example of how consistency pays the bills. Central to Vue Formulate’s inputs is a [comprehensive `context` object](https://vueformulate.com/guide/inputs/slots/#context-object) that dictates virtually everything about an input. The model, validation errors, label value, help text, and lots (lots!) more are members of this object. Because every input has a consistent API, every input has a consistent context object.

{% codepen https://codepen.io/justin-schroeder/pen/rNOQQww %}

While the flexibility to use scoped slots is great — they can hurt the consistency and readability of our form’s code. To address this, Vue Formulate also includes the ability to override the default value of every slot. We call these [“Slot Components”](https://vueformulate.com/guide/inputs/slots/#slot-components), and they’re fundamental to maintaining a clean consistent authoring API. Want to add that example tooltip to every label? No problem. You can replace the default value in the label slot on every input in your project without having to use scoped slots or wrap your components in your templates at all.

If you decide you’re better off creating your own custom input type, you can do that too! Custom inputs keep form authoring buttery-smooth, just pick your own input `type` and register it with Vue Formulate. Your custom input will get validation, labels, help text, model binding, and more out of the box. Even better, once you’ve created a custom input you can easily turn it into a plugin to share with your team members or the larger community.

### Where you go is where I wanna be...

In the excellent Honeypot [Vue documentary](https://www.youtube.com/watch?v=OrxmtDw4pVI), Thorsten Lünborg summed up what I consider to be the number one reasons for Vue’s spectacular success:

> The focus in Vue.js from the get-go was always that the framework is more than just the code. It’s not like, “this is the library, this is the documentation, of how it works, and now you solve the rest.”

In essence, the Vue core team was willing to go where developers were feeling pain points the most. As a result they have created a framework that isn’t just elegant — it’s delightful for real-world developers to use. Vue Formulate maintains this spirit; to meet developer’s pain points with delightful form authoring solutions. We believe we’ve now paved the road for 90% of users — but if your road is less traveled and you find yourself at an edge case — please shout it out. We're listening.

----

If you’re intrigued, checkout [vueformulate.com](https://vueformulate.com/). You can follow me, [Justin Schroeder](https://twitter.com/jpschroeder), on twitter — as well as my co-maintainer [Andrew Boyd](https://twitter.com/BoydDotDev).