Mutt Forms Vue (MFV) is an extension to Mutt Forms, a tool for building HTML forms from JSON Schema definitions, to make it compatible with VueJS. By default, Mutt Forms renders HTML forms directly to the DOM, MFV uses Vue templating system in addition to offering some other benefits - like reactive properties.
MFV was developed in-house at Bought By Many, primarily to get a more robust integration with our VueJS apps. Mutt Forms works directly with the DOM which doesn’t play nicely with Vue, it’s a bit of an anti-pattern to mix these approaches so MFV was born to solve that issue. Like Mutt Forms, it has no dependencies (apart from Vue & Mutt itself) so it’s a tiny addition to any app, and is super fast at rendering even large complicated forms. It’s available for all on a standard MIT license.
Installing
MFV is easily installed from NPM, it’s recommended to use yarn
but npm
works just fine too:
yarn add mutt-forms-vue
Once installed, it can be hooked into Vue like most Vue plugins by using Vue.use()
. This can be done anywhere during the app initialisation:
import Vue from 'vue'
import MuttVue from 'mutt-forms-vue'
Vue.use(MuttVue)
Use with Webpack
MFV, like Mutt Forms, is written in ES6. You can use it directly but you may need to
adjust your babel
setup to have it transpile correctly. To avoid this, a bundled
dist
version is provided where the module has already been transpiled. You can include
this version using the webpack alias syntax:
{
"resolve": {
"alias": {
"mutt-forms$": "node_modules/mutt-forms/dist/mutt-forms.es.js",
"mutt-forms-vue$": "node_modules/mutt-forms-vue/dist/mutt-forms-vue.es.js"
}
}
}
NOTE: Depending on your setup, you may need a vue
alias here also, MFV internally uses Vue templates - so you will need the template compiler, not just the runtime.
Getting started
MFV will extend Vue to add the components ‘mutt-vue’, ‘mutt-widget’ & ‘mutt-watcher’, as well as extending Vue to add a hook directly to Mutt (this is available as this.$mutt
inside components). The components can be used to build forms (and form fragments) directly in Vue templates. In the simplest case, you can just pass a JSON schema to a ‘mutt-vue’ component and you will get a form:
<template>
<div>
<mutt-vue v-bind:schema="schema" v-on:submit=”submitForm”>
</div>
</template>
<script>
export default {
name: 'demo',
data() {
return {
schema: {
name: {
type: 'string'
},
email: {
type: 'string'
}
}
}
}
methods: {
submitForm(form) {
if(form.validate()) {
console.log('Submission!',
JSON.stringify(form.data(), null, 2))
}
}
}
}
</script>
‘mutt-forms-vue’ also takes options, just as Mutt Form objects themselves do - in fact mutt-forms-vue
components will take all of the arguments you might expect to send to a Mutt Form object.
A bit deeper
Under the hood of the mutt-vue
component is simply iterating over (along with some helpful layout & functions) a set of Mutt form fields and renders each one using mutt-widget
. You don’t have to do this however, if you want to create custom layouts or create form fragments you can use the mutt-widget
component directly.
mutt-widget
components expect a field as an argument and will render the corresponding HTML input interface for that field type. The mutt-widget
component is itself polymorphic, and will inspect the field type to determine exactly how it should render. As is usual with Mutt, you can use field options to override default widgets for a given field, MFV will respect this too.
<mutt-widget v-bind:field="field"></mutt-widget>
Getting reactive
The final MFV component is called mutt-watcher
. These can be used to reflect the value of a given field reactively. Internally MFV will make the field value reactive, which means should it change it will update other components reactively. ‘mutt-watcher’ exploits this, so you can create things like form summary panels or more intricate UI’s. As will mutt-widget
, it requires a form field to be bound to it. It will render the field value in a text format in the format field name: <field value>
, there are a few options to aid this display, but by default it will handle all of the data types Mutt understands.
It has a couple of neat uses, for example displaying the value of a hidden field that’s being updated behind the scenes elsewhere and it can even display form fields that aren’t otherwise rendered in the main form.
<mutt-watcher v-bind:field="field"></mutt-watcher>
Hopefully that covers some of the main features of MFV, there is a git repository available with all of these code samples in a working demo app. MFV is still under active development but at this stage it’s API can be considered pretty stable.
(If you end up using MFV in a project, would love to hear your experience!)