{"id":13773688,"url":"https://github.com/JMBeresford/r3f-form","last_synced_at":"2025-05-11T06:30:33.102Z","repository":{"id":65300385,"uuid":"583477267","full_name":"JMBeresford/r3f-form","owner":"JMBeresford","description":"An *accessible* webGL form component library for use with React Three Fiber","archived":false,"fork":false,"pushed_at":"2024-06-01T18:06:58.000Z","size":2207,"stargazers_count":30,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-11-07T18:04:58.036Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://jmberesford.github.io/r3f-form/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JMBeresford.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2022-12-29T22:34:49.000Z","updated_at":"2024-06-12T17:49:08.000Z","dependencies_parsed_at":"2023-01-16T10:15:59.220Z","dependency_job_id":"0fb32e3b-f062-4545-a827-4a9ee036bb29","html_url":"https://github.com/JMBeresford/r3f-form","commit_stats":null,"previous_names":["jmberesford/r3f-input"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JMBeresford%2Fr3f-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JMBeresford%2Fr3f-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JMBeresford%2Fr3f-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JMBeresford%2Fr3f-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JMBeresford","download_url":"https://codeload.github.com/JMBeresford/r3f-form/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225017819,"owners_count":17407832,"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-08-03T17:01:18.986Z","updated_at":"2024-11-17T08:31:26.355Z","avatar_url":"https://github.com/JMBeresford.png","language":"TypeScript","funding_links":[],"categories":["2D GUI"],"sub_categories":["Form"],"readme":"# r3f-form\n\n### [View examples](https://jmberesford.github.io/r3f-form/?path=/story/form--default-submit-button)\n\n\u003e ## WARNING: UNDER HEAVY DEVELOPMENT\n\u003e\n\u003e Each release will aim to be a fully functional and usable release,\n\u003e but breaking API changes WILL be likely for the forseeable future.\n\n## A webGL form component for use with React Three Fiber\n\n![image](https://user-images.githubusercontent.com/1373954/210024281-c735f61a-1a69-45e5-a5d3-147ed57a6c30.png)\n\nThis package aims to create a fully-functional and **accessible** `\u003cForm /\u003e`\ncomponents that can be used within the [@react-three/fiber](https://github.com/pmndrs/react-three-fiber)\necosystem. Ultimately, the goal is to have fully functioning HTML `\u003cform\u003e`s -- with all viable input types -- rendered in webGL.\n\nCurrent implementation binds webGL elements to the existing state and event systems of respective\nhidden HTML DOM elements. There is a heavy reliance on\n[troika-three-text](https://github.com/protectwise/troika/tree/main/packages/troika-three-text)\nfor text-rendering and selection/caret logic.\n\n\u003e Note that `r3f-form` will only work within a React-Three-Fiber Canvas element.\n\u003e You **must** be using\n\u003e\n\u003e - [@react-three/fiber](https://github.com/pmndrs/react-three-fiber)\n\u003e - [@react-three/drei](https://github.com/pmndrs/drei)\n\u003e - [troika-three-text](https://github.com/protectwise/troika/tree/main/packages/troika-three-text)\n\u003e\n\u003e as dependencies in your project to use `r3f-form`.\n\n### Install\n\n```sh\nnpm install r3f-form\n# or\nyarn add r3f-form\n# or\npnpm install r3f-form\n```\n\n# How to use\n\n## Forms\n\nIn order to create a form, just wrap any relevant elements in a `\u003cForm\u003e`:\n\n```tsx\nimport { Form, Input, Label, Submit } from \"r3f-form\";\n\nexport function MyForm() {\n  return (\n    \u003cForm\u003e\n      \u003cLabel text=\"username\" /\u003e\n      \u003cInput name=\"username\" /\u003e\n\n      \u003cLabel text=\"password\" /\u003e\n      \u003cInput name=\"password\" type=\"password\" /\u003e\n\n      \u003cSubmit value=\"Login\" /\u003e\n    \u003c/Form\u003e\n  );\n}\n```\n\n\u003e Note that each element in the form will require a `name` prop in order to be picked up in submission, just like in a normal DOM form element\n\nThe relevant inputs will be bound to respective DOM elements under the hood, and be rendered into the 3D scene like so:\n\n![image](https://user-images.githubusercontent.com/1373954/217718779-816da536-00af-4375-85dd-de707e79aa8d.png)\n\nYou can define submission behavior just like with any old HTML `\u003cform\u003e`:\n\n```tsx\n// redirect to a login script\n\u003cForm action=\"/login.php\"\u003e\u003c/Form\u003e;\n\n// or handle it with a callback\nconst handleSubmit = (e: FormEvent) =\u003e {\n  e.preventDefault();\n\n  const data = new FormData(e.target);\n\n  for (let [name, value] of data.entries()) {\n    console.log(`${name}: ${value}`);\n  }\n};\n\n\u003cForm onSubmit={handleSubmit}\u003e\u003c/Form\u003e;\n```\n\n## Inputs\n\nAn editable text-box bound to an DOM `\u003cinput\u003e` and represented in the webGL canvas.\n\n```ts\ntype Props = {\n  type?: \"text\" | \"password\";\n\n  /** width of the container */\n  width?: number;\n  backgroundColor?: Color;\n  selectionColor?: Color;\n  backgroundOpacity?: number;\n\n  /** [left/right , top/bottom] in THREE units, respectively\n   *\n   * note that height is implicitly defined by the capHeight of the rendered\n   * text. The cap height is dependant on both the `textProps.font` being used and the\n   * `textProps.fontSize` value\n   */\n  padding?: Vector2;\n  cursorWidth?: number;\n\n  /** 3D transformations */\n  position: Vector3;\n  rotation: Euler;\n  scale: Vector3;\n\n  // And ALL props available to DOM \u003cinput\u003es\n};\n```\n\nCreate a basic input field like so:\n\n```tsx\nimport { Input, Label } from \"r3f-form\";\n\nexport function MyInput() {\n  return (\n    \u003c\u003e\n      \u003cLabel text=\"label\" /\u003e\n      \u003cInput /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n![image](https://user-images.githubusercontent.com/1373954/217718847-acb169ed-95ff-4def-a126-491c648346b9.png)\n\nYou can access the value of the input via the `onChange` callback prop:\n\n\u003e The callback is passed the `ChangeEvent` object from the underlying HTML `\u003cinput\u003e`s\n\u003e change event on every change.\n\u003e\n\u003e Read more about this event [here](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event)\n\n```tsx\nimport { Input, Label } from \"r3f-form\";\n\nexport function MyInput() {\n  const [username, setUsername] = React.useState(\"\");\n  // username will always contain the current value\n\n  function handleChange(e) {\n    setUsername(ev.target.value);\n  }\n\n  return (\n    \u003c\u003e\n      \u003cLabel text=\"Test Input\" /\u003e\n      \u003cInput onChange={handleChange} /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\nYou can also create password inputs:\n\n```tsx\nimport { Input, Label } from \"r3f-form\";\n\nexport function MyPassword() {\n  return (\n    \u003c\u003e\n      \u003cLabel text=\"Password\" /\u003e\n      \u003cInput type=\"password\" /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n![image](https://user-images.githubusercontent.com/1373954/217718412-48158e10-53b2-4e79-86c9-54bc5495521a.png)\n\nAdd custom padding to the text container:\n\n```tsx\nimport { Input, Label } from \"r3f-form\";\n\n/*\n * padding: [horizontal padding, vertical padding] in THREE units\n */\n\nexport function MyInput() {\n  return (\n    \u003c\u003e\n      \u003cLabel text=\"Label\" /\u003e\n      \u003cInput padding={[0.05, 0.5]} /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n![image](https://user-images.githubusercontent.com/1373954/217718475-1c696ff1-3b1d-4559-9d02-9535bd59cdff.png)\n\n---\n\n## Textarea\n\n```ts\ntype Props = {\n  /** width of the container */\n  width?: number;\n\n  backgroundColor?: Color;\n  backgroundOpacity?: number;\n  selectionColor?: Color;\n\n  /** [left/right , top/bottom] in THREE units, respectively\n   *\n   * note that height is implicitly defined by the capHeight of the rendered\n   * text. The cap height is dependant on both the `textProps.font` being used\n   * and the `textProps.fontSize` value\n   */\n  padding?: Vector2;\n  cursorWidth?: number;\n\n  /** 3D transformations */\n  position: Vector3;\n  rotation: Euler;\n  scale: Vector3;\n\n  // And ALL props available to DOM \u003ctextarea\u003es\n};\n```\n\nSimilar to the `\u003cInput /\u003e` component, you can also create a `\u003cTextarea /\u003e` like so:\n\n```tsx\nimport { Textarea, Label } from \"r3f-form\";\n\nexport function App() {\n  return (\n    \u003c\u003e\n      \u003cLabel text=\"Default Textarea:\" /\u003e\n      \u003cTextarea /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n![image](https://user-images.githubusercontent.com/1373954/217718566-a718eab7-1e73-4559-96aa-8e14824f0031.png)\n\n---\n\n## Text\n\nIn order to configure the underlying `troika-three-text` instance\nthat is responsible for rendering the actual text, you can use the\n`\u003cText /\u003e` component.\n\nThere is a respective `\u003cInputText /\u003e` or `\u003cTextareaText /\u003e` component for both `\u003cInput /\u003e`s and\n`\u003cTextarea /\u003e`s.\n\nFor all configuration options, check out the [troika docs](https://github.com/protectwise/troika/tree/main/packages/troika-three-text).\n\n\u003e Note that **not all** of troika's props are exposed on these `\u003cText /\u003e`\n\u003e components\n\nChange color and background opacity:\n\n```tsx\nimport { Input, Label, InputText } from \"r3f-form\";\n\nexport function App() {\n  return (\n    \u003c\u003e\n      \u003cLabel text=\"Test Color/Opacity\" /\u003e\n      \u003cInput backgroundOpacity={0.6} backgroundColor=\"black\"\u003e\n        \u003cInputText color=\"red\" /\u003e\n      \u003c/Input\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n![image](https://user-images.githubusercontent.com/1373954/217718611-c2e4848e-8267-4926-9243-7bb61bced61d.png)\n\n```tsx\nimport { Input, Textarea, Label, InputText, TextareaText } from \"r3f-form\";\n\nexport function App() {\n  return (\n    \u003c\u003e\n      \u003cLabel text=\"Test Color/Opacity\" /\u003e\n      \u003cInput\u003e\n        \u003cInputText color=\"#red\" /\u003e\n      \u003c/Input\u003e\n\n      \u003cLabel text=\"Test Textarea\" /\u003e\n      \u003cTextarea\u003e\n        \u003cTextareaText color=\"red\" /\u003e\n      \u003c/Textarea\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n---\n\n## Submit\n\nEquivalent to a DOM `\u003cinput type=\"submit\" /\u003e`, exposed as\nan independent component. By default it renders a button\nusing the following props:\n\n```ts\ntype Props = {\n  value?: string;\n  fontSize?: number;\n  width?: number;\n  height?: number;\n  color?: Color;\n  backgroundColor?: Color;\n\n  /** 3D transformations */\n  position: Vector3;\n  rotation: Euler;\n  scale: Vector3;\n\n  // And ALL props available to DOM \u003cinput\u003es\n};\n```\n\nAdd a simple submit button to your forms like so:\n\n```tsx\n\u003cForm\u003e\n  \u003cLabel text=\"Username\" /\u003e\n  \u003cInput name=\"username\" /\u003e\n\n  \u003cLabel text=\"Password\" /\u003e\n  \u003cInput name=\"password\" type=\"password\" /\u003e\n\n  \u003cSubmit value=\"Login\" /\u003e\n\u003c/Form\u003e\n```\n\n![image](https://user-images.githubusercontent.com/1373954/217718665-c64f6653-f85f-4310-a1c7-f2cf43154f2e.png)\n\nWhile this provides a somewhat-customizable default button, the main purpose of this component\nis to provide a simple interface to use 3D elements to submit your forms. Any children passed in\nwill submit the form on click. For example:\n\n```tsx\n\u003cForm\u003e\n  . . .\n  \u003cSubmit value=\"submit\"\u003e\n    \u003cMySubmitButton /\u003e\n  \u003c/Submit\u003e\n\u003c/Form\u003e\n```\n\n![image](https://user-images.githubusercontent.com/1373954/217718713-a0a6671f-3f1e-4817-9ee9-e205bcc22610.png)\n\nClicking on the big red button would submit the `\u003cForm\u003e`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJMBeresford%2Fr3f-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FJMBeresford%2Fr3f-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJMBeresford%2Fr3f-form/lists"}