{"id":13423990,"url":"https://github.com/fergaldoyle/vue-form","last_synced_at":"2025-04-08T11:07:37.332Z","repository":{"id":57395987,"uuid":"44568579","full_name":"fergaldoyle/vue-form","owner":"fergaldoyle","description":"Form validation for Vue.js 2.2+","archived":false,"fork":false,"pushed_at":"2019-12-13T20:53:21.000Z","size":324,"stargazers_count":613,"open_issues_count":12,"forks_count":90,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-04-01T09:28:21.562Z","etag":null,"topics":["async-validation","form-validation","html5-validation","validation","vue","vuejs2"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fergaldoyle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-10-19T22:48:06.000Z","updated_at":"2025-02-11T21:32:11.000Z","dependencies_parsed_at":"2022-08-30T20:00:59.821Z","dependency_job_id":null,"html_url":"https://github.com/fergaldoyle/vue-form","commit_stats":null,"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fergaldoyle%2Fvue-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fergaldoyle%2Fvue-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fergaldoyle%2Fvue-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fergaldoyle%2Fvue-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fergaldoyle","download_url":"https://codeload.github.com/fergaldoyle/vue-form/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247829491,"owners_count":21002995,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-validation","form-validation","html5-validation","validation","vue","vuejs2"],"created_at":"2024-07-31T00:00:46.254Z","updated_at":"2025-04-08T11:07:37.303Z","avatar_url":"https://github.com/fergaldoyle.png","language":"JavaScript","funding_links":[],"categories":["Awesome Vue.js [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome)","JavaScript","UI实用程序","Components \u0026 Libraries","UI Utilities","Awesome Vue.js","UI Utilities [🔝](#readme)"],"sub_categories":["Libraries \u0026 Plugins","形成","UI Utilities","Form"],"readme":"# vue-form\n\n[![Build Status](https://travis-ci.org/fergaldoyle/vue-form.svg?branch=master)](https://travis-ci.org/fergaldoyle/vue-form)\n\nForm validation for Vue.js 2.2+\n\n### Install\n\nAvailable through npm as `vue-form`.\n\n``` js\nimport VueForm from 'vue-form';\n// or var VueForm = require('vue-form') or window.VueForm if you are linking directly to the dist file\n\n// install globally\nVue.use(VueForm);\nVue.use(VueForm, options);\n\n// or use the mixin\n...\nmixins: [VueForm]\n...\nmixins: [new VueForm(options)]\n...\n```\n\n### Usage\n\nOnce installed you have access to four components (`vue-form`, `validate`, `field`, `field-messages`) for managing form state, validating form fields and displaying validation messages.\n\nLive examples\n* Configured to work with Bootstrap styles: https://jsfiddle.net/fergal_doyle/zfqt4yhq/\n* Matching passwords and password strength: https://jsfiddle.net/fergal_doyle/9rn5kLkw/\n* Field error messages based on submitted state  (labels tied to inputs with `auto-label`): https://jsfiddle.net/fergal_doyle/bqys2p5y/\n\nExample\n\n```html\n\u003cdiv id=\"app\"\u003e\n  \u003cvue-form :state=\"formstate\" @submit.prevent=\"onSubmit\"\u003e\n\n    \u003cvalidate tag=\"label\"\u003e\n      \u003cspan\u003eName *\u003c/span\u003e\n      \u003cinput v-model=\"model.name\" required name=\"name\" /\u003e\n\n      \u003cfield-messages name=\"name\"\u003e\n        \u003cdiv\u003eSuccess!\u003c/div\u003e\n        \u003cdiv slot=\"required\"\u003eName is a required field\u003c/div\u003e\n      \u003c/field-messages\u003e\n    \u003c/validate\u003e\n\n    \u003cvalidate tag=\"label\"\u003e\n      \u003cspan\u003eEmail\u003c/span\u003e\n      \u003cinput v-model=\"model.email\" name=\"email\" type=\"email\" required /\u003e\n\n      \u003cfield-messages name=\"email\"\u003e\n        \u003cdiv slot=\"required\"\u003eEmail is a required field\u003c/div\u003e\n        \u003cdiv slot=\"email\"\u003eEmail is not valid\u003c/div\u003e\n      \u003c/field-messages\u003e\n    \u003c/validate\u003e\n\n    \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n  \u003c/vue-form\u003e\n  \u003cpre\u003e{{ formstate }}\u003c/pre\u003e\n\u003c/div\u003e\n```\n\n```js\nVue.use(VueForm);\n\nnew Vue({\n  el: '#app',\n  data: {\n    formstate: {},\n    model: {\n      name: '',\n      email: 'invalid-email'\n    }\n  },\n  methods: {\n    onSubmit: function () {\n      if(this.formstate.$invalid) {\n        // alert user and exit early\n        return;\n      }\n      // otherwise submit form\n    }\n  }\n});\n```\n\nThe output of `formstate` will be:\n```js\n{\n  \"$dirty\": false,\n  \"$pristine\": true,\n  \"$valid\": false,\n  \"$invalid\": true,\n  \"$submitted\": false,\n  \"$touched\": false,\n  \"$untouched\": true,\n  \"$focused\": false,\n  \"$pending\": false,\n  \"$error\": {\n    // fields with errors are copied into this object\n  },\n  \"$submittedState\": {\n    // each form sumbit, state is cloned into this object\n  },\n  \"name\": {\n    \"$name\": \"name\",\n    \"$dirty\": false,\n    \"$pristine\": true,\n    \"$valid\": false,\n    \"$invalid\": true,\n    \"$touched\": false,\n    \"$untouched\": true,\n    \"$focused\": false,\n    \"$pending\": false,\n    \"$error\": {\n      \"required\": true\n    }\n  },\n  \"email\": {\n    \"$name\": \"email\",\n    \"$dirty\": false,\n    \"$pristine\": true,\n    \"$valid\": false,\n    \"$invalid\": true,\n    \"$touched\": false,\n    \"$untouched\": true,\n    \"$focused\": false,\n    \"$pending\": false,\n    \"$error\": {\n      \"email\": true\n    }\n  }\n}\n```\n\n### Displaying messages\nDisplay validation errors or success messages with `field-messages`.\n\nThe `show` prop supports simple expressions which specifiy when messages should be displayed based on the current state of the field, e.g: `$dirty`, `$dirty \u0026\u0026 $touched`, `$dirty || $touched`, `$touched || $submitted`, `$focused \u0026\u0026 ($dirty || $submitted)`\n\n```html\n\u003cfield-messages name=\"name\" show=\"$dirty \u0026\u0026 $touched\"\u003e\n  \u003cdiv slot=\"errorKeyA\"\u003eError message A\u003c/div\u003e\n  \u003cdiv slot=\"errorKeyB\"\u003eError message B\u003c/div\u003e\n\u003c/field-messages\u003e\n```\n\nOr use scoped templates:\n```html\n\u003cfield-messages name=\"fieldName\"\u003e\n  \u003cspan\u003eSuccess\u003c/span\u003e\n  \u003ctemplate slot=\"required\" scope=\"state\"\u003e\n    \u003cspan v-if=\"state.$touched || state.$submitted\"\u003eName is a required field\u003c/span\u003e\n  \u003c/template\u003e\n  \u003ctemplate slot=\"errorKeyB\" scope=\"state\"\u003e\n    \u003cspan v-if=\"state.$touched || state.$dirty\"\u003eError message B\u003c/span\u003e\n  \u003c/template\u003e\n\u003c/field-messages\u003e\n```\n\n### Validators\n\n```\ntype=\"email\"\ntype=\"url\"\ntype=\"number\"\nrequired\nminlength\nmaxlength\npattern\nmin (for type=\"number\")\nmax (for type=\"number\")\n\n```\n\nYou can use static validation attributes or bindings. If it is a binding, the input will be re-validated every binding update meaning you can have inputs which are conditionally required etc.\n```html\n\u003c!-- static validators --\u003e\n\u003cvalidate\u003e\n  \u003cinput type=\"email\" name=\"email\" v-model=\"model.email\" required /\u003e\n\u003c/validate\u003e\n\u003cvalidate\u003e\n  \u003cinput type=\"text\" name=\"name\" v-model=\"model.name\" maxlength=\"25\" minlength=\"5\" /\u003e\n\u003c/validate\u003e\n\n\u003c!-- bound validators --\u003e\n\u003cvalidate\u003e\n  \u003cinput type=\"email\" name=\"email\" v-model=\"model.email\" :required=\"isRequired\" /\u003e\n\u003c/validate\u003e\n\u003cvalidate\u003e\n  \u003cinput type=\"text\" name=\"name\" v-model=\"model.name\" :maxlength=\"maxLen\" :minlength=\"minLen\" /\u003e\n\u003c/validate\u003e\n```\n\n#### Custom validators\nYou can register global and local custom validators.\n\nGlobal custom validator\n```js\n\nvar options = {\n  validators: {\n    'my-custom-validator': function (value, attrValue, vnode) {\n      // return true to set input as $valid, false to set as $invalid\n      return value === 'custom';\n    }\n  }\n}\n\nVue.use(VueForm, options);\n// or\n// mixins: [new VueForm(options)]\n```\n\n```html\n\u003cvalidate\u003e\n  \u003cinput v-model=\"something\" name=\"something\" my-custom-validator /\u003e\n  \u003c!--\n    slot name inside field-messages would be: \u003cdiv slot=\"my-custom-validator\"\u003e...\u003c/div\u003e\n  --\u003e\n\u003c/validate\u003e\n```\n\nLocal custom validator\n```js\n// ...\nmethods: {\n  customValidator: function (value) {\n    // return true to set input as $valid, false to set as $invalid\n    return value === 'custom';\n  }\n},\n// local custom validator can also be a data or computed property\ncomputed: {\n  isEmailAvailable: function () {\n    // return true to set input as $valid, false to set as $invalid\n  }\n}\n// ...\n```\n\n```html\n\u003cvalidate :custom=\"{customValidator: customValidator, 'email-available': isEmailAvailable}\"\u003e\n  \u003cinput v-model=\"something\" name=\"something\" /\u003e\n  \u003c!--\n    slot name inside field-messages would be: \u003cdiv slot=\"customValidator\"\u003e...\u003c/div\u003e\n  --\u003e\n\u003c/validate\u003e\n```\n\n#### Async validators:\n\nAsync validators are custom validators which return a Promise. `resolve()` `true` or `false` to set field validity.\n```js\n// ...\nmethods: {\n  customValidator (value) {\n    return new Promise((resolve, reject) =\u003e {\n      setTimeout(() =\u003e {\n        resolve(value === 'ajax');\n      }, 100);\n    });\n  }\n}\n// ...\n```\n\nAsync validator with debounce (example uses lodash debounce)\n```js\nmethods: {\n  debounced: _.debounce(function (value, resolve, reject) {\n    fetch('https://httpbin.org/get').then(function(response){\n      resolve(response.isValid);\n    });\n  }, 500),\n  customValidator (value) {\n    return new Promise((resolve, reject) =\u003e {\n      this.debounced(value, resolve, reject);\n    });\n  }\n}\n```\n\n### Reset state\n```\n\u003cvue-form ref=\"form\" :state=\"formstate\"\u003e\n\nresetState: function () {\n  this.formstate._reset();\n  // or\n  this.$refs.form.reset();\n}\n```\n\n### State classes\nAs form and input validation states change, state classes are added and removed\n\nPossible form classes:\n```\nvf-form-dirty, vf-form-pristine, vf-form-valid, vf-form-invalid, vf-form-submitted, vf-form-focused- vf-form-pending\n```\n\nPossible input classes:\n```\nvf-dirty, vf-pristine, vf-valid, vf-invalid, vf-focused, vf-pending\n\n// also for every validation error, a class will be added, e.g.\nvf-invalid-required, vf-invalid-minlength, vf-invalid-max, etc\n```\n\nInput wrappers (e.g. the tag the `validate` component renders) will also get state classes, but with the `field` prefix, e.g.\n```\nvf-field-dirty, vf-field-pristine, vf-field-valid, vf-field-invalid, vf-field-focused, vf-field-pending\n```\n\n### Custom components\n\nWhen writing custom form field components, e.g. `\u003cmy-checkbox v-model=\"foo\"\u003e\u003c/my-checkbox\u003e` you should trigger the `focus` and `blur` events after user interaction either by triggering native dom events on the root node of your component, or emitting Vue events (`this.$emit('focus)`) so the `validate` component can detect and set the `$dirty` and `$touched` states on the field.\n\n### Component props\n\n#### vue-form\n* `state` Object on which form state is set\n* `tag` String, defaults to `form`\n* `show-messages` String, applies to all child `field-messages`, show errors dependant on form field state e.g. `$touched`, `$dirty || $touched`, '$touched || $submitted'\n\n#### validate\n* `state` Optional way of passing in the form state. If omitted form state will be found in the $parent\n* `custom` Object containing one or many custom validators. `{validatorName: validatorFunction}`\n* `tag` String which specifies what element tag should be rendered by the `validate` component, defaults to `span`\n* `auto-label`: Boolean, defaults to false. Automatically set `for` and `id` attributes of label and input elements found inside the `validate` component\n* `debounce` Number, defaults to none, which specifies the delay (milliseconds) before validation takes place.\n\n#### field-messages\n* `state` Optional way of passing in the form state. If omitted form state will be found in the $parent\n* `name` String which specifies the related field name\n* `tag` String, defaults to `div`\n* `show` String, show error dependant on form field state e.g. `$touched`, `$dirty || $touched`, '$touched || $submitted'\n* `auto-label` Boolean, defaults to false. Automatically set the `for` attribute of labels found inside the `field-messages` component\n\n#### field\n* `tag` String, defaults to `div`\n* `auto-label` Boolean, defaults to true. Automatically set `for` and `id` attributes of label and input elements found inside the `validate` component\n\n### Config\nSet config options when using `Vue.use(VueForm, options)`, or when using a mixin `mixins: [new VueForm(options)]` defaults:\n\n```js\n{\n    validators: {},\n    formComponent: 'vueForm',\n    formTag: 'form',\n    messagesComponent: 'fieldMessages',\n    messagesTag: 'div',\n    showMessages: '',\n    validateComponent: 'validate',\n    validateTag: 'div',\n    fieldComponent: 'field',\n    fieldTag: 'div',\n    formClasses: {\n      dirty: 'vf-form-dirty',\n      pristine: 'vf-form-pristine',\n      valid: 'vf-form-valid',\n      invalid: 'vf-form-invalid',\n      touched: 'vf-form-touched',\n      untouched: 'vf-form-untouched',\n      focused: 'vf-form-focused',\n      submitted: 'vf-form-submitted',\n      pending: 'vf-form-pending'\n    },\n    validateClasses: {\n      dirty: 'vf-field-dirty',\n      pristine: 'vf-field-pristine',\n      valid: 'vf-field-valid',\n      invalid: 'vf-field-invalid',\n      touched: 'vf-field-touched',\n      untouched: 'vf-field-untouched',\n      focused: 'vf-field-focused',\n      submitted: 'vf-field-submitted',\n      pending: 'vf-field-pending'\n    },\n    inputClasses: {\n      dirty: 'vf-dirty',\n      pristine: 'vf-pristine',\n      valid: 'vf-valid',\n      invalid: 'vf-invalid',\n      touched: 'vf-touched',\n      untouched: 'vf-untouched',\n      focused: 'vf-focused',\n      submitted: 'vf-submitted',\n      pending: 'vf-pending'\n    },\n    Promise: typeof Promise === 'function' ? Promise : null\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffergaldoyle%2Fvue-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffergaldoyle%2Fvue-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffergaldoyle%2Fvue-form/lists"}