Vue form components with server side validation in mind
FormVuelar is a set of predefined vue form components which are designed to automatically display errors coming back from your backend. It works out of the box with the error message bag that is returned by Laravel when submitting an ajax form.
Examples
Give it a try!
Features
- Works out of the box with Laravel
- Axios integration
- File upload support including process indicator
- Dropzone with image preview (inspired by FilePont)
- Display validation error messages from error response
Getting Started
npm install formvuelar --save
Available Components
The following components are shipped with FormVuelar:
Name | Description | Import Name |
---|
<fvl-form /> | Form wrapper element | import { FvlForm } from 'formvuelar' |
<fvl-input /> | Input field | import { FvlInput } from 'formvuelar' |
<fvl-textarea /> | Text area field | import { FvlTextarea } from 'formvuelar' |
<fvl-radio /> | Radio input field | import { FvlRadio } from 'formvuelar' |
<fvl-checkbox /> | Check box input field | import { FvlCheckbox } from 'formvuelar' |
<fvl-select /> | Select input field | import { FvlSelect } from 'formvuelar' |
<fvl-file /> | File input field | import { FvlFile } from 'formvuelar' |
<fvl-multi-file /> | Multi file input field | import { FvlMultiFile } from 'formvuelar' |
<fvl-dropzone /> | Dropzone field | import { FvlDropzone } from 'formvuelar' |
<fvl-submit /> | Submit button | import { FvlSubmit } from 'formvuelar' |
Components Props & Events
Name | Prop/Event | Type | Default | Possible values | Notes |
---|
fvl-form | :method | String | 'post' | get |post |put |patch |delete | |
| :data | Object | {} | {} | |
| :url | String | null | | |
| :multipart | Boolean | false | true |false | |
| @success | Function | | axios response | |
| @error | Function | | axios error response | |
| @upload-progress | Function | | 0-100 | |
| | | | | |
fvl-input | :value.sync | Data | '' | form.name | |
| :id | String | null | | |
| :name | String | '' | | |
| :label | String | null | | |
| :type | String | 'text' | | |
| :placeholder | String | null | | |
| :autocomplete | String | null | | |
| :field-class | String | null | | |
| :min | Number | null | | |
| :max | Number | null | | |
| :size | Number | null | | |
| :step | Number | null | | |
| :required | Boolean | false | true |false | |
| :readonly | Boolean | false | true |false | |
| :disabled | Boolean | false | true |false | |
| :pattern | String | null | regex | |
| | | | | |
fvl-textarea | :value.sync | Data | '' | form.about | |
| :id | String | null | | |
| :name | String | '' | | |
| :label | String | null | | |
| :placeholder | String | null | | |
| :autocomplete | String | null | | |
| :field-class | String | null | | |
| :cols | Number | null | | |
| :maxlength | Number | null | | |
| :rows | Number | null | | |
| :wrap | Boolean | null | hard |soft | |
| :required | Boolean | false | true |false | |
| :readonly | Boolean | false | true |false | |
| :disabled | Boolean | false | true |false | |
| :pattern | String | null | regex | |
| | | | | |
fvl-select | :selected.sync | Data | null | form.favoriteColor | |
| :options | Object | {} | {'key': 'value', ...} | |
| :id | String | null | | |
| :name | String | '' | | |
| :label | String | null | | |
| :allow-empty | Boolean | false | true |false | |
| :placeholder | String | null | | |
| :autocomplete | String | null | | |
| :required | Boolean | false | true |false | |
| :readonly | Boolean | false | true |false | |
| :disabled | Boolean | false | true |false | |
| | | | | |
fvl-radio | :checked.sync | Data | null | form.newsletter | |
| :options | Object | {} | {'key': 'value', ...} | |
| :id | String | null | | |
| :name | String | '' | | |
| :label | String | null | | |
| :required | Boolean | false | true |false | |
| :readonly | Boolean | false | true |false | |
| :disabled | Boolean | false | true |false | |
fvl-checkbox | :checked.sync | Data | null | form.terms | |
| :id | String | null | | |
| :name | String | '' | | |
| :label | String | null | | |
| :required | Boolean | false | true |false | |
| :readonly | Boolean | false | true |false | |
| :disabled | Boolean | false | true |false | |
| | | | | |
fvl-file | :file.sync | Data | null | form.avatar | |
| :id | String | null | | |
| :name | String | '' | | |
| :label | String | null | | |
| :required | Boolean | false | true |false | |
| :readonly | Boolean | false | true |false | |
| :disabled | Boolean | false | true |false | |
| | | | | |
fvl-multi-file | :files.sync | Data | null | form.gallery | |
| :id | String | null | | |
| :name | String | '' | | |
| :label | String | null | | |
| :required | Boolean | false | true |false | |
| :readonly | Boolean | false | true |false | |
| :disabled | Boolean | false | true |false | |
| | | | | |
fvl-dropzone | :files.sync | Data | null | form.media | |
| :id | String | null | | |
| :name | String | '' | | |
| :label | String | null | | |
| :required | Boolean | false | true |false | |
| :readonly | Boolean | false | true |false | |
| :disabled | Boolean | false | true |false | |
| | | | | |
fvl-submit | :loader | Boolean | false | true |false | |
| :disabled | Boolean | false | true |false | |
Basic Form Template
Create a form and sent it via post request to your server.
<fvl-form method="post" :data="form" url="/create">
<fvl-input
:value.sync="form.fullname"
label="Full Name"
name="fullname"
/>
<fvl-textarea
:value.sync="form.bio"
label="Bio"
name="bio"
/>
<fvl-radio
:checked.sync="form.pet"
:options="{'cat': 'Cat', 'dog': 'Dog'}"
label="Favorite pet"
name="pet"
/>
<fvl-submit>Validate</fvl-submit>
</fvl-form>
The form object you pass into the form component above would look like this:
import { FvlForm, FvlInput, FvlTextarea, FvlRadio, FvlSubmit } from 'formvuelar'
...
components: {
FvlForm,
FvlInput,
FvlTextarea,
FvlRadio,
FvlSubmit,
},
data() {
return {
form: {
fullname: '',
bio: '',
pet: ''
},
...
Error Response
The response from your Backend should contain a Json error object and have a status of 422 in order to show the error messages below the input fields. This response format is default for Laravel and will work out of the box.
{
"message": "The given data was invalid.",
"errors": {
"field-1": [
"Error 1",
"Error 2"
],
"field-2": [
"Error 1",
"Error 2"
]
}
}
Client side validation
You can still use the default HTML5 validation rules for all input fields like 'accept' and 'required' for file inputs:
<fvl-file
label="Avatar"
name="avatar"
:file.sync="form.avatar"
accept="image/*"
required
/>
Styling
The styling is totally up to you. All components have their own classes so you have full control over the look and feel of every component.
Every component is wrapped with a div and the corresponding class .fvl-{type}-wrapper.
Labels have a class name of .fvl-{type}-label.
The field itself has a class name of .fvl-{type}
Example classes of the text input component (using Tailwind)
.fvl-input-wrapper {
@apply p-2;
}
.fvl-input-label {
@apply block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2;
}
.fvl-input {
@apply appearance-none block w-full bg-grey-lighter text-grey-darkest border border-grey-lighter rounded py-3 px-4 leading-tight;
}
I'm using Tailwind CSS for the examples.
Feel free to use the predefined css component classes for your own projects.
TODO
- Advanced select component with search and remote source option
- Tags component