{"id":16853669,"url":"https://github.com/alex-oleshkevich/vue-forms-kit","last_synced_at":"2026-05-19T14:10:02.448Z","repository":{"id":145545181,"uuid":"332575248","full_name":"alex-oleshkevich/vue-forms-kit","owner":"alex-oleshkevich","description":"A set of primitives to build your own forms and inputs with low effort.","archived":false,"fork":false,"pushed_at":"2021-02-21T17:43:35.000Z","size":295,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-08T05:57:36.538Z","etag":null,"topics":["forms","inputs","vue"],"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/alex-oleshkevich.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-24T22:59:41.000Z","updated_at":"2021-02-21T17:43:34.000Z","dependencies_parsed_at":"2023-04-08T10:17:22.277Z","dependency_job_id":null,"html_url":"https://github.com/alex-oleshkevich/vue-forms-kit","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/alex-oleshkevich/vue-forms-kit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alex-oleshkevich%2Fvue-forms-kit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alex-oleshkevich%2Fvue-forms-kit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alex-oleshkevich%2Fvue-forms-kit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alex-oleshkevich%2Fvue-forms-kit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alex-oleshkevich","download_url":"https://codeload.github.com/alex-oleshkevich/vue-forms-kit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alex-oleshkevich%2Fvue-forms-kit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278897292,"owners_count":26064780,"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","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["forms","inputs","vue"],"created_at":"2024-10-13T13:52:40.872Z","updated_at":"2025-10-08T05:57:36.972Z","avatar_url":"https://github.com/alex-oleshkevich.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Vue Forms kit\n\nA set of primitives to build your own forms and inputs with low effort.\n\n## Installation\n\n```bash\nyarn install vue-forms-kit\n# or\nnpm i vue-forms-kit\n```\n\n**Note:** The package does not provide transpiled JavaScript files. Use it with module bundlers.\n\n## Architecture\n\nUnlike many other libraries, this one aims to provide a low-level set of renderless components\nthat you may compose to create a higher lever form inputs. The library doesn't enforce any styling\ndeferring that decision to a developer. It also ships with a collection of ready-to-use form inputs\nthat you can style and use in your project, or use them as a reference. Moreover, it is better\nto implement your form components in the project using these components.\n\nThe core building blocks are input, form group, and form.\n\n-   \"input\" is the most simple form element that renders a native form element or Vue component.\n-   \"form group\" is an optional decorator for the input component that enhances it with extra functionality like errors, help text, or labels.\n-   \"form\" is an (optional) element, that operates with user input data, performs validation, and can handle the form submission.\n    It also propagates validation errors to the child form groups.\n\n## Quick start\n\nIn this mini-tutorial, we are going to create a simple form with form groups and form inputs.\nThis form will ask for user information, perform validation and submit the data.\nThe tutorial assumes that you are familiar with scoped slots.\n\n### Form inputs\n\nLet's start with the smallest entity - the form input:\n\n```html\n\u003cscript\u003e\n    // TextInput.vue\n    import { InputController } from 'vue-forms-kit';\n\n    export default {\n        components: { InputController },\n    };\n\u003c/script\u003e\n\u003ctemplate\u003e\n    \u003cinput-controller v-on=\"$listeners\" v-slot=\"{onInput}\"\u003e\n        \u003cinput type=\"text\" v-bind=\"$attrs\" @input=\"onInput\" /\u003e\n    \u003c/input-controller\u003e\n\u003c/template\u003e\n```\n\nWe just created a simple text input. In real life, you would need handlers for \"change\", \"focus\", and \"blur\" events. At this stage, you can already start using the `\u003ctext-input /\u003e` component in your forms.\n\n### Form groups\n\nOkay, let's decorate it with a label, with help text and validation errors.\nFirst, we will create a \"form group\" component that will receive label text and help text via properties.\n\n```html\n\u003cscript\u003e\n    // FormGroup.vue\n    import { FormGroupController } from 'vue-forms-kit';\n\n    export default {\n        components: { FormGroupController },\n        props: {\n            label: String,\n            help: String,\n        },\n    };\n\u003c/script\u003e\n\u003ctemplate\u003e\n    \u003cform-group-controller v-slot=\"{required, errors}\"\u003e\n        \u003cdiv class=\"form-group\"\u003e\n            \u003clabel class=\"form-label\"\u003e\n                \u003cspan\u003e{{ label }}\u003c/span\u003e\n                \u003cspan class=\"form-label-asterisk\" v-if=\"required\"\u003e*\u003c/span\u003e\n            \u003c/label\u003e\n            \u003cslot\u003e\u003c/slot\u003e\n            \u003cdiv v-if=\"help\" class=\"form-help\"\u003e{{ help }}\u003c/div\u003e\n            \u003cul v-if=\"errors\" class=\"form-errors\"\u003e\n                \u003cli v-for=\"(error, index) in errors\" :key=\"error + index\"\u003e\n                    {{ error}}\n                \u003c/li\u003e\n            \u003c/ul\u003e\n        \u003c/div\u003e\n    \u003c/form-group-controller\u003e\n\u003c/template\u003e\n```\n\nWe created a form group component that decorates `TextInput`. You can implement any other features like icons, floating labels, and so on. The usage may look like this:\n\n```html\n\u003cform-group label=\"Your email\" help=\"The email address must include @ sign\"\u003e\n    \u003ctext-input name=\"email\"\u003e\n\u003c/form-group\u003e\n```\n\n### Form fields\n\nWhen you have many forms it feels like you are writing a lot of boilerplate code.\nLet's reduce it by introducing a new concept: \"form fields\". The form field is a component that combines inputs and form groups into a new one.\n\n```html\n\u003cscript\u003e\n    // TextField.vue\n    import TextInput from './TextInput.vue';\n    import FormGroup from './FormGroup.vue';\n\n    export default {\n        components: { TextInput, FormGroup },\n        props: {\n            label: String,\n            help: String,\n        },\n    };\n\u003c/script\u003e\n\u003ctemplate\u003e\n    \u003cform-group :label=\"label\" :help=\"help\"\u003e\n        \u003ctext-input v-bind=\"$attrs\" v-on=\"$listeners\" /\u003e\n    \u003c/form-group\u003e\n\u003c/template\u003e\n```\n\nNow our form becomes cleaner:\n\n```html\n\u003ctext-field\n    name=\"email\"\n    label=\"Your email\"\n    help=\"The email address must include @ sign\"\n\u003e\u003c/text-field\u003e\n```\n\n### Forms\n\nOnce we have building blocks, let's create our form component with these requirements:\n\n-   it must validate email address length and report an error when invalid\n-   it must submit the form via our function\n-   it must render errors returned by the submit handler\n\nWe won't create a new Vue component for the form in this example. So let's use `FormController` to achieve our goal.\nThe form controller requires the following properties:\n\n-   `data` - the object containing all user input\n-   `handler` - a function that handles form submission\n-   `validator` - an optional function that performs validation. It must return a key-value mapping where keys are field names and values are errors for the field.\n\n```html\n\u003cscript\u003e\n    // EditUserForm.vue\n    import { FormController } from 'vue-forms-kit';\n    import TextField from './TextField.vue';\n\n    export default {\n        components: { FormController, TextField },\n        data() {\n            return {\n                formData: {\n                    first_name: '',\n                    last_name: '',\n                    email: '',\n                },\n            };\n        },\n        methods: {\n            async validate(formData) {\n                let errors = {};\n                if (!formData.email) {\n                    errors.email = 'This field is required.';\n                }\n                return errors;\n            },\n            async submit(formData) {\n                async function wait() {\n                    return new Promise((resolve, reject) =\u003e {\n                        setTimeout(() =\u003e {\n                            if (formData.email.indexOf('error') !== -1) {\n                                reject({\n                                    message: 'Form submission error.',\n                                    errors: {\n                                        email: 'This value is invalid.',\n                                    },\n                                });\n                            } else {\n                                resolve();\n                            }\n                        }, 1000);\n                    });\n                }\n                await wait();\n            },\n        },\n    };\n\u003c/script\u003e\n\u003ctemplate\u003e\n    \u003cform-controller\n        :data=\"formData\"\n        :handler=\"submit\"\n        :validator=\"validate\"\n        v-slot=\"{state, message}\"\n    \u003e\n        \u003cdiv v-if=\"message\"\u003eError message: {{ message }}\u003c/div\u003e\n        \u003ctext-field\n            name=\"first_name\"\n            label=\"First name\"\n            v-model=\"formData.first_name\"\n        /\u003e\n        \u003ctext-field\n            name=\"last_name\"\n            label=\"Last name\"\n            v-model=\"formData.last_name\"\n        /\u003e\n        \u003ctext-field\n            type=\"email\"\n            name=\"email\"\n            label=\"Email\"\n            required\n            v-model=\"formData.email\"\n        /\u003e\n        \u003cbutton type=\"submit\" :disabled=\"state === 'loading'\"\u003eSubmit\u003c/button\u003e\n    \u003c/form-controller\u003e\n\u003c/template\u003e\n```\n\nThe form is ready to use. I want to point you at some moments.\nFirst, the form exposes the `state` property that you can use to react to form state transition.\nFor example, we disabled the submit button while the form was handling the submission.\nSecond, if the API returns an error message, we can display it to use. Use the `message` key to access the message value.\n\nIf you want to test error response, include \"error\" string in the email input.\nFor example, \"error@example.com\".\n\nMore information about validation, submission, and error handling you can find in other sections.\n\n## Form Validation\n\nThe form validation triggers right before the form submission.\nThe validator is a pure JavaScript function that receives `formData` as the first argument and returns an object where keys are field names and values are error messages.\n\nHere is an example of such function:\n\n```javascript\nfunction validator(formData) {\n    let errors = {};\n    if (!formData.email) {\n        errors.email = 'This field is required'.\n    }\n    return errors;\n}\n```\n\n## Submit handlers\n\nSimilar to validators, submit handlers are pure async JavaScript functions.\nThey accept `formData` as the first argument.\nThe `FormController` component will handle exceptions or promise rejections and try to guess the error message and field errors.\n\n### Handling response errors\n\nIf the submit handler throws an exception or returns promise rejection, the form controller\nwill try to get message and field errors from this object.\nIn other words, in case of error your submit handler has to raise an exception which has \"message\" and \"errors\" properties or return a promise rejection:\n\n```javascript\n// exception based\nclass CustomError extends Error {\n    constructor(message, errors) {\n        this.message = message;\n        this.errors = errors;\n    }\n}\nfunction submitWithExceptionRaised() {\n    throw new CustomError('Submission error', {\n        email: 'This field is not a valid email address'.,\n    });\n}\n\n// promise based\nfunction submitWithPromiseRejection() {\n    return Promise.reject({\n        message: 'Submission error',\n        errors: {\n            email: 'This field is not a valid email address'.,\n        }\n    })\n}\n```\n\nYou can make your own error handler either by passing `errorHandler` property of the form controller or make it global by setting `Config.responseErrorHandler` parameter.\n\n```html\n\u003cscript\u003e\n    // CustomErrorHandler.vue\n    import { FormController } from 'vue-forms-kit';\n\n    export default {\n        components: { FormController },\n        methods: {\n            submit() {\n                return Promise.reject({\n                    data: {\n                        message: 'Rejected',\n                        errors: {},\n                    },\n                });\n            },\n            async errorHandler(response) {\n                // response is the promise rejection value seen in submit() method.\n                let { message, errors } = response.data;\n                return { message, errors };\n            },\n        },\n    };\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n    \u003cform-controller\n        :data=\"{}\"\n        :handler=\"submit\"\n        :error-handler=\"errorHandler\"\n        v-slot=\"{ message }\"\n    \u003e\n        \u003cp\u003e{{ message }}\u003c/p\u003e\n        \u003cbutton\u003eSubmit\u003c/button\u003e\n    \u003c/form-controller\u003e\n\u003c/template\u003e\n```\n\n## Configuration\n\nYou can set global response error handler via exported `Config` object:\n\n```javascript\nimport { Config } from 'vue-forms-kit';\n\nConfig.responseErrorHandler = response =\u003e {\n    let { message, errors } = response;\n    return { message, errors };\n};\n```\n\n## API\n\n### InputController\n\n#### Properties\n\n---\n\n| Name           | Type   | Default value | Comment                           |\n| -------------- | ------ | ------------- | --------------------------------- |\n| input-selector | string | -             | A selector for the input element. |\n\n#### Events\n\n| Name   | Data       | Comment                                                                                                |\n| ------ | ---------- | ------------------------------------------------------------------------------------------------------ |\n| input  | any        | Triggered on user input. Carries the value of \"input\" event of the underlying form element.            |\n| change | any        | Triggered when input value changes. Carries the value of \"input\" event of the underlying form element. |\n| focus  | FocusEvent | Same as HTML focus event.                                                                              |\n| blur   | FocusEvent | Same as HTML blue event.                                                                               |\n\n### FormGroupController\n\n#### Properties\n\n| Name   | Type               | Default value | Comment                 |\n| ------ | ------------------ | ------------- | ----------------------- |\n| errors | string \\| string[] | []            | A list of field errors. |\n\n#### Events\n\nNo public events emitted.\n\n### FormController\n\n#### Properties\n\n| Name      | Type     | Default value | Comment                                   |\n| --------- | -------- | ------------- | ----------------------------------------- |\n| data      | object   | (required)    | Key-value object containing user input.   |\n| handler   | function | (required)    | A form submission handler.                |\n| validator | function | () =\u003e ({})    | A form validator.                         |\n| errors    | object   | {}            | Key-value object containing field errors. |\n\n#### Events\n\n| Name     | Data | Comment                                                             |\n| -------- | ---- | ------------------------------------------------------------------- |\n| response | any  | Triggered after submission handler has been successfully completed. |\n| error    | any  | Fired then submission handler finished with an error.               |\n\n## Interfaces\n\n```typescript\ntype FormData = { [key: string]: any };\ntype ValidationErrors = { [key: string]: any };\n\ntype ValidatorInterface = (formData: FormData) =\u003e ValidationErrors;\n\ninterface SubmitResponse {\n    message?: string;\n    errors?: ValidationErrors;\n}\ntype SubmitHandler = (formData: FormData) =\u003e SubmitResponse;\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falex-oleshkevich%2Fvue-forms-kit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falex-oleshkevich%2Fvue-forms-kit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falex-oleshkevich%2Fvue-forms-kit/lists"}