{"id":15013057,"url":"https://github.com/ver01/form","last_synced_at":"2025-10-04T19:03:16.540Z","repository":{"id":34645550,"uuid":"176667750","full_name":"ver01/form","owner":"ver01","description":"React JsonSchema drived dynamic form engine. Support theme (antd...) assign","archived":false,"fork":false,"pushed_at":"2022-12-09T19:45:07.000Z","size":1829,"stargazers_count":9,"open_issues_count":16,"forks_count":65,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-25T23:51:20.442Z","etag":null,"topics":["form","json-schema","json-schema-form","jsonschema","react","react-form","schema","ver01"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ver01.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-03-20T06:18:39.000Z","updated_at":"2025-03-12T12:04:46.000Z","dependencies_parsed_at":"2023-01-15T08:19:03.331Z","dependency_job_id":null,"html_url":"https://github.com/ver01/form","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ver01%2Fform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ver01%2Fform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ver01%2Fform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ver01%2Fform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ver01","download_url":"https://codeload.github.com/ver01/form/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248514429,"owners_count":21116963,"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":["form","json-schema","json-schema-form","jsonschema","react","react-form","schema","ver01"],"created_at":"2024-09-24T19:43:40.375Z","updated_at":"2025-10-04T19:03:11.477Z","avatar_url":"https://github.com/ver01.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Table of Contents\n\n  - [Online Demo](#online-demo)\n  - [local Demo](#local-demo)\n  - [import npm package](#import-npm-package)\n  - [Uncontrolled Mode](#uncontrolled-mode)\n  - [Controlled Mode](#controlled-mode)\n  - [Requirement](#requirement)\n  - [Theme](#theme)\n     - [Official theme](#official-theme)\n     - [Custom theme](#custom-theme)\n        - [Component Schema](#component-schema)\n        - [Dynamic props generator rule](#dynamic-props-generator-rule)\n           - [for props](#for-props)\n           - [for WidgetComponentSchema](#for-widgetcomponentschema)\n     - [Value](#value)\n        - [Value In](#value-in)\n           - [Uncontrolled Mode](#uncontrolled-mode)\n           - [Controlled Mode](#controlled-mode)\n        - [Value Out](#value-out)\n        - [Validate](#validate)\n     - [JSON Schema Support](#json-schema-support)\n        - [$vf_opt](#vf_opt)\n           - [$vf_opt.props](#vf_opt-props)\n           - [$vf_opt.widget](#vf_opt-widget)\n           - [$vf_opt.option](#vf_opt-option)\n           - [$vf_opt.validate](#vf_opt-validate)\n\n---\n\n# Details \u0026 Demo by visite official site [https://ver01.com](https://ver01.com)\n\n\n# Start\n\u003e __Ver01Form__ is standalone lib for render JsonSchem to React Form，with different react themes supports.\n\n\n\n## Online Demo\n\n[![CodeSandbox Demo](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/embed/0mlpp16yy0)\n\n\n[Schema Playground](https://ver01.com/form/playground/index.html)\n\n\n## local Demo\n\n\n\n`git clone git@github.com:ver01/form.git`\n\n`npm install`\n\n`npm run start`\n\nvisit http://localhost:8888 for schema demo\n\n# Initialize\n\n## import npm package\n\n* Core npm package is __@ver01/form__.\n\n* Most of times you need using it with theme (eg: @ver01/form-theme-antd). Or you can define theme by yourself.\n\n## Uncontrolled Mode\n\n* With defaultValue props\n\n```react\n\u003cVer01Form\n    schema={{\n        title: \"Uncontrolled Mode:\",\n        type: \"string\"\n    }}\n    defaultValue=\"hello World\"\n    onChange={this.onChange.bind(this)}\n/\u003e\n```\n\n\u003e [Live Demo](https://codesandbox.io/embed/211nx6j9kn?fontsize=14) \n\n## Controlled Mode\n\n* with defaultValue props\n\n```react\n\u003cVer01Form\n    schema={{\n        title: \"Controlled Mode:\",\n        type: \"string\"\n    }}\n    value={this.state.value}\n    onChange={this.onChange.bind(this)}\n/\u003e\n```\n\n\u003e [Live Demo](https://codesandbox.io/embed/vy2237jl0l?fontsize=14)\n\n# Theme\n\nNow antd theme avaliavle now, others will come soon.\n\nissue you wanted most react theme~~ (1 theme in at most 1 week)\n\n## Requirement\n\n* @ver01/form is standalone lib. No other package needed\n* But, you need import form theme package. Which may involve other react component framework (most of time includes in your project already).\n\n## Theme\n\n### Official theme\n\n* [antd](https://github.com/ver01/form-theme-antd)\n\n### Custom theme\n\n#### Component Schema\n\nWe assigned a json like schema to define react componet.\n\nThe entry file [like this](https://github.com/ver01/form-theme-antd/blob/master/src/index.js).\n\nTheme entry file should export structure like this:\n\n```react\n// Export Theme\nexport default {\n    validators: {\n        // buildin just need msgBuilder\n        minLength: ({ value, ruleValue, schema }) =\u003e ({\n            errorType: \"feedbackStr\",\n            errorData: `should NOT be shorter than ${ruleValue} characters`,\n        }),\n        ...\n        // custom need checkLogic\n        otherCustomValidLogic\n    },\n    components: {\n        // 5base type\n        string: {\n            getWidget: [({ schema }) =\u003e ({\n                widgetName: \"readonly\",\n                widgetData: { text: \"True\"},\n            })], // special widget pick logic: return { widgetName, widgetData }\n            widgets: {\n                select: {\n                    formatter: val =\u003e (val ? \"true\" : \"false\"), // format value to componet\n                    normalizer: val =\u003e (val === \"true\" ? true : false), // format value to output\n                    component: FormItem, // react component\n            \t\t    propsMixinList: [\"style\"], // user defined in JsonSchema $vf extend config\n                    props: formItemProps, // component props defined in other place\n                    children: [ // component children (recursion)\n                        {\n                            component: Select, \n            \t\t\t\tpropsMixinList: [\"placeholder\"],\n                            props: { // props can dynamic generate with $vf_ prefix; more detail see [Dynamic props generator rule] section below\n                                $vf_value: ({ value }) =\u003e value,\n                                $vf_onChange: ({ handle }) =\u003e handle.onChange\n                            }\n                        }\n                    ]\n                },\n                radio: radioWidget // defined as select widget\n            }, // widget define: { [widgetName]: WidgetComponentSchema }\n            errorObjGenerator:({ errors }) =\u003e {\n                const errorMessage = [];\n                errors.map(error =\u003e {\n                    const { errorType, errorData } = error;\n                    switch (errorType) {\n                        default:\n                            errorMessage.push(errorData);\n                            break;\n                    }\n                });\n                // return as errorObj\n                return errorMessage.length\n                    ? {\n                    message: (\n                        \u003cul\u003e\n                            {errorMessage.map((it, ind) =\u003e (\n                                \u003cli key={ind}\u003e{it}\u003c/li\u003e\n                            ))}\n                        \u003c/ul\u003e\n                    ),\n                }\n                : null;\n            }, // generator errorObj for WidgetComponentSchema render widget\n        },\n        number,\n        integer,\n        boolean,\n        null,\n        // 1root only(for body holder)\n        root,\n        // 1control only(for control schema oneof anyof allof)\n        control,\n        // 2container\n        array,\n        object,\n    },\n};\n\n```\n\n\n\n#### Dynamic props generator rule\n\n##### for props\n\n```javascript\n {\n    isRoot: true,\n\n    rootValue: {},\n    rootSchema: {},\n\n    parentSchema: {},\n\n    value: {},\n    schema: {},\n\n    objectKey: \"a\",\n    arrayIndex: 3,\n\n    handle: {\n        onChange: () =\u003e {},\n        // for array\n        canMoveUp: false,\n        canMoveDown: false,\n        canAppend: false,\n        canRemove: false,\n        moveUp: () =\u003e {},\n        moveDown: () =\u003e {},\n        append: () =\u003e {},\n        remove: () =\u003e {},\n        // for control\n        hasSchemaControl: true, // child formnode has SchemaList\n        schemaList: [{ schema: {}, valid: true, selected: true }], // no control is null\n        schemaSelect: ind =\u003e {\n            /* aform func */\n        },\n    },\n\n    schemaOption: {\n        // read by schema.$vf_opt.option\n        // for array:\n        orderable: true,\n        removable: true,\n        appendable: true,\n        // for string:\n        disabled: false,\n        readonly: false,\n        fileHandle: () =\u003e {}, // ?\n        // for object:\n        order: [\"key_a\", \"key_b\"],\n    },\n\n    formProps: {\n        validators: {},\n    },\n\n    formOption: {},\n\n    errorObj: {\n        // custom\n    },\n};\n```\n\n##### for WidgetComponentSchema\n\n```javascript\n{\n    formatter: () =\u003e {},\n    normalizer: () =\u003e {},\n}\n```\n\n### Value\n\n#### Value In\n\n##### Uncontrolled Mode\n\n* You need set the defaultValue props\n* unset defaultValue \u0026 value props also caused ver01Form in Uncontrolled Mode\n* The Form will use the defaultValue in first defined, __deal with some situation defaultValue set async__\n\n```react\n// uncontrolled Mode:\n\u003cVer01Form\n  schema={{ type: 'string'}}\n  defaultValue='helloWorld'\n  onChange={console.info}\n/\u003e\n```\n\n##### Controlled Mode\n\n- You need set the value props.\n- onChange will trigger new value, but form will change when value changed.\n\n```react\n// Controlled Mode:\n\u003cVer01Form\n  schema={{ type: 'string'}}\n  value={this.state.value}\n  onChange={value=\u003ethis.setValue({value})}\n/\u003e\n```\n\n#### Value Out\n\nWe not export some value post method, you can get value by onChange event, then deal with it as you wish\n\n```react\nrender(){\nreturn \u003cdiv\u003e\n  \u003cVer01Form\n    schema={{ type: 'string'}}\n    value={this.state.value}\n    onChange={value=\u003ethis.setValue({value})}\n  /\u003e\n  \u003cButton onClick={()=\u003e{postServer(this.state.value)}}\u003eSubmit\u003c/Button\u003e\n\u003c/div\u003e\n}\n```\n\n#### Validate\n\nvalidate result will export by onValidate method\n\nwhen validate failed, error set as:\n\n* validateErrValuePath: the path which part valued valid failed.\n* errorObj: Generate by [Component Schema](#Component Schema) errorObjGenerator function.\n* errors: Generate by [Component Schema](#Component Schema) validators function\n  * return as array\n  * [{  errorType: \"errorTypeString\", errorData: AnyType }]\n\n```react\nrender(){\nreturn \u003cdiv\u003e\n  \u003cVer01Form\n    schema={{\n      \"type\": \"object\",\n      \"required\": [\n          \"firstName\",\n      ],\n      \"properties\": {\n          \"firstName\": {\n              \"type\": \"string\"\n          }\n      }\n    }}\n    value={{ firstName: '' }} // zero length string cause required check\n    onValidate={error=\u003ethis.setState({errors: error \u0026\u0026 error.errors})} // error : { [validateErrValuePath]: {errorObj, errors} }\n  /\u003e\n  \u003cButton onClick={()=\u003e{\n    if (this.state.errors){\n      postServer(this.state.value);\n    }else {\n      console.info(this.state.errors);\n    }\n  }\u003eSubmit\u003c/Button\u003e\n\u003c/div\u003e\n}\n```\n\n### JSON Schema Support\n\n#### $vf_opt\n\nwe extended JSON Schema By $vf_opt section\n\n##### $vf_opt.props\n\nwill mixin to all components belone to one value node. Filtered by  [Component Schema](#Component Schema) propsMixinList\n\n##### $vf_opt.widget\n\nstring, assign the component used. Defined in  [Component Schema](#Component Schema) widgets\n\n##### $vf_opt.option\n\n* For array\n  * orderable(default true)\n  * addable(default true)\n  * removeable(default true)\n* For string\n  * disabled\n  * readonly\n* For object\n  * order: ['first-key', 'second-key', '*', 'last-key']\n\n##### $vf_opt.validate\n\n\\[ruleName\\]: ruleValue\n\nsee sample-validation  [local demo](#local demo)\n\nValidate can be defined in formProps or buildin validate\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fver01%2Fform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fver01%2Fform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fver01%2Fform/lists"}