{"id":20753502,"url":"https://github.com/dpck/form","last_synced_at":"2026-04-18T21:33:14.692Z","repository":{"id":50807344,"uuid":"169545643","full_name":"dpck/form","owner":"dpck","description":"The Bootstrap Form Component For Entering Data.","archived":false,"fork":false,"pushed_at":"2021-05-28T22:44:04.000Z","size":758,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-18T22:38:28.189Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://dpck.github.io/form/","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/dpck.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2019-02-07T09:14:33.000Z","updated_at":"2020-01-23T17:02:19.000Z","dependencies_parsed_at":"2022-08-27T19:40:29.597Z","dependency_job_id":null,"html_url":"https://github.com/dpck/form","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpck%2Fform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpck%2Fform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpck%2Fform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpck%2Fform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dpck","download_url":"https://codeload.github.com/dpck/form/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243057252,"owners_count":20229174,"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":[],"created_at":"2024-11-17T09:13:44.078Z","updated_at":"2025-12-12T00:00:19.920Z","avatar_url":"https://github.com/dpck.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @depack/form\n\n[![npm version](https://badge.fury.io/js/%40depack%2Fform.svg)](https://www.npmjs.com/package/@depack/form)\n\n`@depack/form` is The Bootstrap Form Component For Entering Data.\n\n\u003ca alt=\"Depack Demo\" href=\"https://dpck.github.io/form/\"\u003e![@depack/form demo](doc/demo.gif)\u003c/a\u003e\n\u003cbr\u003e\u003ca alt=\"Depack Demo\" href=\"https://dpck.github.io/form/\"\u003eClick For The Demo\u003c/a\u003e\n\n```sh\nyarn add -E @depack/form\n```\n\n## Table Of Contents\n\n- [Table Of Contents](#table-of-contents)\n- [API](#api)\n  * [**Form**](#form)\n  * [**FormGroup**](#formgroup)\n  * [**Input**](#input)\n  * [**Select**](#select)\n  * [**Textarea**](#textarea)\n  * [**SubmitForm**](#submitform)\n    * [`reset(): void`](#reset-void)\n  * [**SubmitButton**](#submitbutton)\n- [Custom Components](#custom-components)\n- [Copyright](#copyright)\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/0.svg?sanitize=true\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n## API\n\nThe package is available by importing its default and named functions:\n\n```js\nimport Form, {\n  FormGroup, Input, TextArea, Select,\n} from '@depack/form'\n```\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/1.svg?sanitize=true\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n### **Form**\n\nCreates the form that maintains the values of each field that is found inside its children. Any additional properties will be passed down to the form. Each child component will receive `values` in its context.\n\n\u003cstrong\u003e\u003ca name=\"type-_depackformformprops\"\u003e`_depackForm.FormProps`\u003c/a\u003e\u003c/strong\u003e: Options for the Form component.\n\n|   Name   |        Type        |                                     Description                                     |\n| -------- | ------------------ | ----------------------------------------------------------------------------------- |\n| onChange | \u003cem\u003e!Function\u003c/em\u003e | The callback to call when a change is made to any of the inputs inside of the form. |\n| formRef  | \u003cem\u003e!Function\u003c/em\u003e | The function to call with the reference to the form HTML.                           |\n| onSubmit | \u003cem\u003e!Function\u003c/em\u003e | The function to call on form submit.                                                |\n\n```jsx\nimport Form, {\n  FormGroup, TextArea, Input, Select, SubmitButton, SubmitForm,\n} from '@depack/form'\n\nclass ExampleForm extends SubmitForm {\n  render({ onChange, ...props }) {\n    const { formLoading, error, success } = this.state\n\n    return (\u003cForm {...props} onSubmit={this.submit.bind(this)} onChange={values =\u003e {\n      this.reset()\n      if(onChange) onChange(values)\n    }}\u003e\n      \u003cFormGroup label=\"Input\" help=\"Type in something...\"\u003e\n        \u003cInput name=\"input\" value=\"hello-world\" /\u003e\n      \u003c/FormGroup\u003e\n      \u003cFormGroup label=\"Select\" help=\"Please select...\"\u003e\n        \u003cSelect name=\"select\" value=\"2\" options={[\n          {\n            title: 'Free will',\n            value: '1',\n          },\n          {\n            title: 'Unfree will',\n            value: '2',\n          },\n        ]} /\u003e\n      \u003c/FormGroup\u003e\n      \u003cFormGroup label=\"TextArea\" help=\"Multiple row input...\"\u003e\n        \u003cTextArea name=\"textarea\"\u003e\n          One must still have chaos in oneself to be able to give birth to a dancing star.\n        \u003c/TextArea\u003e\n      \u003c/FormGroup\u003e\n      \u003cSubmitButton loading={formLoading} type=\"warning\"\n        confirmText=\"Submit Data\" /\u003e\n      {error \u0026\u0026 `Error: ${error}`}\n      {success \u0026\u0026 `OK`}\n    \u003c/Form\u003e)\n  }\n}\n\nexport default ExampleForm\n```\n```html\n\u003cform\u003e\n  \u003cdiv class=\"form-group\"\u003e\n    \u003clabel for=\"i70984\"\u003eInput\u003c/label\u003e\n    \u003cinput name=\"input\" class=\"form-control\" value=\"hello-world\" type=\"text\"\n      aria-describedby=\"hi70984\" id=\"i70984\"\u003e\n    \u003csmall id=\"hi70984\" class=\"form-text text-muted\"\u003eType in something...\u003c/small\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"form-group\"\u003e\n    \u003clabel for=\"i97426\"\u003eSelect\u003c/label\u003e\n    \u003cselect name=\"select\" class=\"custom-select\" id=\"i97426\"\n      aria-describedby=\"hi97426\"\u003e\n      \u003coption value\u003e\u003c/option\u003e\n      \u003coption value=\"1\"\u003eFree will\u003c/option\u003e\n      \u003coption selected value=\"2\" selected\u003eUnfree will\u003c/option\u003e\n    \u003c/select\u003e\n    \u003csmall id=\"hi97426\" class=\"form-text text-muted\"\u003ePlease select...\u003c/small\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"form-group\"\u003e\n    \u003clabel for=\"i20008\"\u003eTextArea\u003c/label\u003e\n    \u003ctextarea name=\"textarea\" aria-describedby=\"hi20008\" class=\"form-control\"\n      id=\"i20008\" rows=\"3\"\u003eOne must still have chaos in oneself to be able to give birth to a dancing star.\u003c/textarea\u003e\n    \u003csmall id=\"hi20008\" class=\"form-text text-muted\"\u003eMultiple row input...\u003c/small\u003e\n  \u003c/div\u003e\n  \u003cbutton class=\"btn btn-warning\" type=\"submit\"\u003eSubmit Data\u003c/button\u003e\n\u003c/form\u003e\n```\n\n\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e\u003cimg src=\"doc/ExampleForm.png\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/2.svg?sanitize=true\" width=\"15\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n### **FormGroup**\n\nThe form group is used to represent a logical combination of a label, input, help text and validation error message. The _FormGroup_ component generates `id` and `hid` values and passes them to children components in the context.\n\n\u003cstrong\u003e\u003ca name=\"type-_depackformformgroupprops\"\u003e`_depackForm.FormGroupProps`\u003c/a\u003e\u003c/strong\u003e: Options for the FormGroup component.\n\n|      Name      |       Type       |                                                                                          Description                                                                                           |\n| -------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| label          | \u003cem\u003estring\u003c/em\u003e  | The label to display for the group.                                                                                                                                                            |\n| className      | \u003cem\u003estring\u003c/em\u003e  | The additional class name to add to `form-group`.                                                                                                                                              |\n| labelClassName | \u003cem\u003estring\u003c/em\u003e  | The additional class name to add to the label.                                                                                                                                                 |\n| col            | \u003cem\u003estring\u003c/em\u003e  | If any of the `col` properties are passed (e.g., `col-12`, `col-sm-8`, _etc_), they will be set on the label.                                                                                  |\n| row            | \u003cem\u003eboolean\u003c/em\u003e | Whether the group should be displayed in a row. Children must manually be wrapped in `div`s with `col` classes. Adds the `col-form-label` class to the label and the `row` class to the group. |\n| form-row       | \u003cem\u003eboolean\u003c/em\u003e | Same as `row`, but adds the `form-row` class to the group.                                                                                                                                     |\n| details        | \u003cem\u003eboolean\u003c/em\u003e | Whether to display the group in `details` block.                                                                                                                                               |\n| help           | \u003cem\u003estring\u003c/em\u003e  | The help text to show in `＜small className=\"form-text text-muted\"＞{help}＜/small＞`. To support validation with `valid` and `invalid` classes, set help on inputs rather than group.             |\n\n```jsx\nimport Form, { FormGroup, Input } from '@depack/form'\n\nconst Example = () =\u003e (\n  \u003cForm\u003e\n    \u003cFormGroup\n      label=\"What is your name?\"\n      help=\"Your name, your name, what is your name?\"\n    \u003e\n      \u003cInput /\u003e\n    \u003c/FormGroup\u003e\n  \u003c/Form\u003e\n)\n```\n```html\n\u003cform\u003e\n  \u003cdiv class=\"form-group\"\u003e\n    \u003clabel for=\"i70984\"\u003eWhat is your name?\u003c/label\u003e\n    \u003cinput class=\"form-control\" type=\"text\" aria-describedby=\"hi70984\" id=\"i70984\"\u003e\n    \u003csmall id=\"hi70984\" class=\"form-text text-muted\"\u003e\n      Your name, your name, what is your name?\u003c/small\u003e\n  \u003c/div\u003e\n\u003c/form\u003e\n```\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/3.svg?sanitize=true\" width=\"15\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n### **Input**\n\nThe input is a one-line entry field.\n\n\u003cstrong\u003e\u003ca name=\"type-_depackforminputprops\"\u003e`_depackForm.InputProps`\u003c/a\u003e\u003c/strong\u003e: The rest is all other options to be passed to the input element. When compiling with _Depack_, the props must be added like `\u003cInput {...({ 'onClick': test })}\u003e`.\n\n|    Name     |       Type       |                                                                          Description                                                                          | Default |\n| ----------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |\n| required    | \u003cem\u003eboolean\u003c/em\u003e | Whether this is a required field.                                                                                                                             | -       |\n| name        | \u003cem\u003estring\u003c/em\u003e  | The input name.                                                                                                                                               | -       |\n| placeholder | \u003cem\u003estring\u003c/em\u003e  | The input placeholder.                                                                                                                                        | -       |\n| file        | \u003cem\u003eboolean\u003c/em\u003e | Whether the input is for selecting files.                                                                                                                     | -       |\n| value       | \u003cem\u003estring\u003c/em\u003e  | The initial value.                                                                                                                                            | -       |\n| className   | \u003cem\u003estring\u003c/em\u003e  | The additional class name to add to `form-control` and `form-control-file`.                                                                                   | -       |\n| col         | \u003cem\u003estring\u003c/em\u003e  | If any of the `col` properties are passed (e.g., `col-12`, `col-sm-8`, _etc_), the _Form_ will create a `div` wrapper around the input with the column class. | -       |\n| type        | \u003cem\u003estring\u003c/em\u003e  | The input type.                                                                                                                                               | `text`  |\n| help        | \u003cem\u003estring\u003c/em\u003e  | The help text to show under the input. Supports validation classes.                                                                                           | -       |\n| invalid     | \u003cem\u003eboolean\u003c/em\u003e | Adds the `invalid-feedback` class to help text.                                                                                                               | -       |\n| valid       | \u003cem\u003eboolean\u003c/em\u003e | Adds the `valid-feedback` class to help text.                                                                                                                 | -       |\n\n```jsx\nimport { Input } from '@depack/form'\n\nconst Example = () =\u003e (\n  \u003cInput\n    name=\"example\"\n    placeholder=\"enter the value...\"\n    value=\"initial value\"\n    type=\"text\"\n    required\n  /\u003e\n)\n```\n```html\n\u003cinput required name=\"example\" placeholder=\"enter the value...\"\n  class=\"form-control\" value=\"initial value\" type=\"text\"\u003e\n```\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/4.svg?sanitize=true\" width=\"15\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n### **Select**\n\nThis element present the values to select from.\n\n\u003cstrong\u003e\u003ca name=\"type-_depackformselectprops\"\u003e`_depackForm.SelectProps`\u003c/a\u003e\u003c/strong\u003e: Options for the Select component.\n\n|    Name     |                        Type                        |                                                                          Description                                                                           |\n| ----------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| required    | \u003cem\u003eboolean\u003c/em\u003e                                   | Whether this is a required field.                                                                                                                              |\n| name        | \u003cem\u003estring\u003c/em\u003e                                    | The select name.                                                                                                                                               |\n| value       | \u003cem\u003estring\u003c/em\u003e                                    | The initial value.                                                                                                                                             |\n| col         | \u003cem\u003estring\u003c/em\u003e                                    | If any of the `col` properties are passed (e.g., `col-12`, `col-sm-8`, _etc_), the _Form_ will create a `div` wrapper around the select with the column class. |\n| className   | \u003cem\u003estring\u003c/em\u003e                                    | The additional class name to add to `custom-select`.                                                                                                           |\n| defaultText | \u003cem\u003e?string\u003c/em\u003e                                   | The default option's text. Pass `null` to disable the default option.                                                                                          |\n| options     | \u003cem\u003e!Array\u0026lt;{ value: *, title: string }\u0026gt;\u003c/em\u003e | The array with options to render inside of the `select` element.                                                                                               |\n\n```jsx\nimport { Select } from '@depack/form'\n\nconst Example = () =\u003e (\n  \u003cSelect name=\"example\" required value=\"1\"\n    options={[\n      { value: 1, title: 'hello' },\n      { value: 2, title: 'world' },\n    ]}\u003e\n  \u003c/Select\u003e\n)\n```\n```html\n\u003cselect name=\"example\" class=\"custom-select\" required\u003e\n  \u003coption value\u003e\u003c/option\u003e\n  \u003coption selected value=\"1\" selected\u003ehello\u003c/option\u003e\n  \u003coption value=\"2\"\u003eworld\u003c/option\u003e\n\u003c/select\u003e\n```\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/5.svg?sanitize=true\" width=\"15\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n### **Textarea**\n\nThe input field with multiple lines. The child of the component will set the initial value inside of the textarea.\n\n\u003cstrong\u003e\u003ca name=\"type-_depackformtextareaprops\"\u003e`_depackForm.TextAreaProps`\u003c/a\u003e\u003c/strong\u003e: Options for the TextAreaProps component.\n\n|    Name     |       Type       |               Description               | Default |\n| ----------- | ---------------- | --------------------------------------- | ------- |\n| required    | \u003cem\u003eboolean\u003c/em\u003e | Whether this is a required field.       | -       |\n| name        | \u003cem\u003estring\u003c/em\u003e  | The textarea name.                      | -       |\n| placeholder | \u003cem\u003estring\u003c/em\u003e  | The textarea placeholder.               | -       |\n| rows        | \u003cem\u003enumber\u003c/em\u003e  | How many rows should the textarea have. | `3`     |\n\n```jsx\nimport { TextArea } from '@depack/form'\n\nconst Example = () =\u003e (\n  \u003cTextArea name=\"example\" rows=\"4\" required\n    placeholder=\"enter the multiline value...\"\u003e\n    Hello World\n  \u003c/TextArea\u003e\n)\n```\n```html\n\u003ctextarea required name=\"example\" placeholder=\"enter the multiline value...\"\n  class=\"form-control\" rows=\"4\"\u003eHello World\u003c/textarea\u003e\n```\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/6.svg?sanitize=true\" width=\"15\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n### **SubmitForm**\n\nThis class extends the `Preact.Component` and implements the `submit` method which will send the data to the server and await for the response while setting the `formLoading` property of the state to `true`. The `error` and `success` properties will also be set upon the arrival of data, with the JSON response being used to extract the error. The `submitFinish` callback can be used to receive the result of the form submission. Components implementing this abstract class must write their own render method.\n\n\u003cstrong\u003e\u003ca name=\"type-_depackformsubmitformprops\"\u003e`_depackForm.SubmitFormProps`\u003c/a\u003e\u003c/strong\u003e: Options for the SubmitForm component.\n\n|     Name     |                Type                 |                                    Description                                    |\n| ------------ | ----------------------------------- | --------------------------------------------------------------------------------- |\n| __path*__    | \u003cem\u003estring\u003c/em\u003e                     | The path where to send data.                                                      |\n| submitFinish | \u003cem\u003e(arg0: Object) =\u003e !Promise\u003c/em\u003e | The callback after the data has been sent with possible response from the server. |\n\n\u003cstrong\u003e\u003ca name=\"type-_depackformsubmitformstate\"\u003e`_depackForm.SubmitFormState`\u003c/a\u003e\u003c/strong\u003e: The state structure for the SubmitForm.\n\n|       Name       |       Type        |                    Description                    |\n| ---------------- | ----------------- | ------------------------------------------------- |\n| __formLoading*__ | \u003cem\u003eboolean\u003c/em\u003e  | Whether the data has been sent for submission.    |\n| __error*__       | \u003cem\u003e?string\u003c/em\u003e  | The error returned by the server.                 |\n| __success*__     | \u003cem\u003e?boolean\u003c/em\u003e | Whether the form has been submitted successfully. |\n\n```jsx\nimport Form, { SubmitForm, Input } from '@depack/form'\n\nclass DataForm extends SubmitForm {\n  render() {\n    const { error, success, formLoading } = this.state\n    return (\u003cForm onSubmit={this.submit.bind(this)}\u003e\n      \u003cInput name=\"example\" /\u003e\n      {error \u0026\u0026 `Error: ${error}`}\n      {success \u0026\u0026 'Success!'}\n      \u003cbutton type=\"submit\" disabled={formLoading}\u003eSubmit\u003c/button\u003e\n    \u003c/Form\u003e)\n  }\n}\nconst Example = () =\u003e (\n  \u003cDataForm path=\"/send-data\" submitFinish={() =\u003e {\n    console.log('hooray!')\n  }} /\u003e\n)\n```\n```html\n\u003cform\u003e\u003cinput name=\"example\" class=\"form-control\" type=\"text\"\u003e\u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\u003c/form\u003e\n```\n\n#### \u003ccode\u003e\u003cins\u003ereset\u003c/ins\u003e(): \u003ci\u003evoid\u003c/i\u003e\u003c/code\u003e\n\nResets the `error` and `success` properties of the form.\n\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/7.svg?sanitize=true\" width=\"15\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n### **SubmitButton**\n\nThe button that can be placed inside the form and used for submission since it has `type=\"submit\"` property. It also has the `loading` property to disable the button and show the spinning wheel indicator.\n\n\u003cstrong\u003e\u003ca name=\"type-_depackformsubmitbuttonprops\"\u003e`_depackForm.SubmitButtonProps`\u003c/a\u003e\u003c/strong\u003e: Options for the SubmitButton component.\n\n|       Name       |       Type       |                                                                              Description                                                                              |  Default  |\n| ---------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |\n| loading          | \u003cem\u003eboolean\u003c/em\u003e | Whether the button should display as loading.                                                                                                                         | `false`   |\n| loadingText      | \u003cem\u003estring\u003c/em\u003e  | The text to show during the loading progress.                                                                                                                         | -         |\n| __confirmText*__ | \u003cem\u003estring\u003c/em\u003e  | The text for the normal state.                                                                                                                                        | -         |\n| className        | \u003cem\u003estring\u003c/em\u003e  | The class name, such as `btn-lg`.                                                                                                                                     | -         |\n| type             | \u003cem\u003estring\u003c/em\u003e  | The type of the button to add to the class as `btn-{type}`. One of `('primary' \\| 'secondary' \\| 'success' \\| 'danger' \\| 'warning' \\| 'info' \\| 'light' \\| 'dark')`. | `primary` |\n| outline          | \u003cem\u003eboolean\u003c/em\u003e | Display the outline style of the button via setting the `btn-outline-{type}` class.                                                                                   | `false`   |\n| disabled         | \u003cem\u003eboolean\u003c/em\u003e | Whether the button is disabled. It becomes disabled when the form is loading by default.                                                                              | `false`   |\n\n```jsx\nimport { SubmitButton } from '@depack/form'\n\nconst Example = ({ formLoading }) =\u003e (\n  \u003cSubmitButton type=\"light\" confirmText=\"Add Data\"\n    loading={formLoading} loadingText=\"Loading...\" outline=\"1\" /\u003e\n)\n```\n```html\n\u003cbutton class=\"btn btn-outline-light\" type=\"submit\"\u003eAdd Data\u003c/button\u003e\n```\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/8.svg?sanitize=true\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n## Custom Components\n\nTo implement a custom component, one must write a class component that would report its initial value in `componentDidMount` method via the `onChange` method that it receives in the context. Overall, there are 4 properties that a component can receive in the context:\n\n- `id`: If placed in the _FormGroup_, this will be set to the ID that the component should set on the input so that the label can focus on it on click.\n- `hid`: If placed in the _FormGroup_, this will be set to auto-generated value for the help field.\n- `values`: This is the overall values hash containing all the values of the fields in the form. It is set by the _Form_ parent component.\n- `onChange`: This is the callback set by the _Form_ to report changes to the values of the component. It must also be fired after the component is mounted to set its initial model value in the form (i.e. update the `values` field).\n\nThe components are controlled which means their values are set via the model, and are contained in the `values` context property. Whenever an update is needed, the `onChange` method has to be fired. To allow server-side rendering of the component when the initial value is not going to be reported to the _Form_ via the `componentDidMount`, it must be set manually after checking if `values` contain the name of the component. If the component for some reason is going to be used also outside of the form, the `values` must be defaulted to `{}`.\n\nHere is an example of the _Input_ component which accounts for all the above points:\n\n```jsx\nimport { Component } from 'preact'\nimport { shouldComponentUpdate, getClasses } from './lib'\nimport Help from './help'\n\nexport default class Input extends Component {\n  constructor() {\n    super()\n    /** @type {!_depackForm.InputProps} */\n    this.props = this.props\n  }\n  shouldComponentUpdate(newProps, __, newContext) {\n    const res = shouldComponentUpdate.call(this, newProps, newContext)\n    return res\n  }\n  componentDidMount() {\n    const { value, name } = this.props\n    const { onChange } = this.context\n    if (value !== undefined \u0026\u0026 onChange) onChange(name, value)\n  }\n  /**\n   * Triggers the onchange event on the form.\n   * @param {string} value\n   */\n  onChange(value) {\n    this.context.onChange(this.props.name, value)\n  }\n  /**\n   * @param {!_depackForm.InputProps} [props]\n   */\n  render({\n    required, name, placeholder, type = 'text', file, value, className,\n    invalid, valid, help, ...props\n  }) {\n    const { colClasses, prop } = getClasses(props)\n    const c = [\n      `form-control${file ? '-file' : ''}`, className,\n      invalid ? 'is-invalid' : null,\n      valid ? 'is-valid' : null,\n    ]\n      .filter(Boolean).join(' ')\n    const { hid, id, values = {} } = this.context\n    const rendered = name in values // for SSR\n    const input = (\u003cinput\n      required={required}\n      name={name}\n      placeholder={placeholder}\n      className={c}\n      value={rendered ? values[name] : value}\n      type={type}\n      aria-describedby={hid}\n      id={id}\n      onChange={(e) =\u003e {\n        this.onChange(e.currentTarget.value)\n      }}\n      {...prop}\n    /\u003e)\n    if (colClasses.length) {\n      const he = help ? (\u003cHelp help={help} hid={hid} valid={valid} invalid={invalid} /\u003e) : null\n      return (\u003cdiv className={colClasses.join(' ')}\u003e\n        {input}\n        {he}\n      \u003c/div\u003e)\n    }\n    return input\n  }\n}\n\n/**\n * @suppress {nonStandardJsDocs}\n * @typedef {import('../types').InputProps} _depackForm.InputProps\n */\n```\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/9.svg?sanitize=true\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n## Copyright\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003e\n      \u003ca href=\"https://artd.eco\"\u003e\n        \u003cimg width=\"100\" src=\"https://raw.githubusercontent.com/wrote/wrote/master/images/artdeco.png\"\n          alt=\"Art Deco\"\u003e\n      \u003c/a\u003e\n    \u003c/th\u003e\n    \u003cth\u003e© \u003ca href=\"https://artd.eco\"\u003eArt Deco\u003c/a\u003e for \u003ca href=\"https://artd.eco/depack\"\u003eDepack\u003c/a\u003e 2020\u003c/th\u003e\n    \u003cth\u003e\n      \u003ca href=\"https://www.technation.sucks\" title=\"Tech Nation Visa\"\u003e\n        \u003cimg width=\"100\" src=\"https://raw.githubusercontent.com/idiocc/cookies/master/wiki/arch4.jpg\"\n          alt=\"Tech Nation Visa\"\u003e\n      \u003c/a\u003e\n    \u003c/th\u003e\n    \u003cth\u003e\u003ca href=\"https://www.technation.sucks\"\u003eTech Nation Visa Sucks\u003c/a\u003e\u003c/th\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003cp align=\"center\"\u003e\u003ca href=\"#table-of-contents\"\u003e\n  \u003cimg src=\"/.documentary/section-breaks/-1.svg?sanitize=true\"\u003e\n\u003c/a\u003e\u003c/p\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpck%2Fform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdpck%2Fform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpck%2Fform/lists"}