{"id":13801126,"url":"https://github.com/bilus/reforms","last_synced_at":"2026-02-21T01:31:28.052Z","repository":{"id":33888383,"uuid":"37600803","full_name":"bilus/reforms","owner":"bilus","description":"Beautiful Bootstrap 3 forms for Om, Reagent and Rum.","archived":false,"fork":false,"pushed_at":"2017-02-08T16:30:27.000Z","size":6356,"stargazers_count":168,"open_issues_count":4,"forks_count":7,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-10-24T17:12:32.449Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bilus.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-06-17T14:43:49.000Z","updated_at":"2024-04-01T08:26:59.000Z","dependencies_parsed_at":"2022-08-17T19:55:09.715Z","dependency_job_id":null,"html_url":"https://github.com/bilus/reforms","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/bilus/reforms","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bilus%2Freforms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bilus%2Freforms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bilus%2Freforms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bilus%2Freforms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bilus","download_url":"https://codeload.github.com/bilus/reforms/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bilus%2Freforms/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29670124,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T00:11:43.526Z","status":"ssl_error","status_checked_at":"2026-02-20T23:52:33.807Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2024-08-04T00:01:19.782Z","updated_at":"2026-02-21T01:31:28.019Z","avatar_url":"https://github.com/bilus.png","language":"Clojure","funding_links":[],"categories":["Awesome ClojureScript"],"sub_categories":["Miscellaneous"],"readme":"# Reforms\n\nA Clojurescript library that lets you build beautiful data-binding forms with [Om](https://github.com/omcljs/om), [Reagent](https://github.com/reagent-project/reagent) and [Rum](https://github.com/tonsky/rum).\n\nYou can write code that is fully portable between Reagent, Om and Rum making it easier to reuse code and giving you a clear migration path.\n\nTo help you quickly create beautiful forms without messing with CSS, the generated markup is compatible with [Bootstrap 3](http://getbootstrap.com/) CSS\nand [Font Awesome](http://fortawesome.github.io/Font-Awesome/). For quick results simply include Bootstrap and Font Awesome CSS.\n\nIf you think something useful is missing though, please let me know.   \n\n\u003cimg src=\"https://github.com/bilus/reforms/blob/master/doc/images/sample.png\" width=\"70%\"\u003e\n\nA good place to see the available controls: [demo](http://bilus.github.io/reforms/examples/controls/index.html).\n\n\u003c!-- To install doctoc: git npm install -g doctoc --\u003e\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n\n- [Usage](#usage)\n  - [Getting started with Om](#getting-started-with-om)\n  - [Getting started with Reagent](#getting-started-with-reagent)\n  - [Getting started with Rum](#getting-started-with-rum)\n  - [External CSS](#external-css)\n  - [Quick tutorial](#quick-tutorial)\n    - [Hello, world!](#hello-world)\n    - [Data binding](#data-binding)\n  - [Prettying it up](#prettying-it-up)\n    - [Adding a placeholder](#adding-a-placeholder)\n    - [Changing orientation](#changing-orientation)\n    - [Wrapping in a panel](#wrapping-in-a-panel)\n    - [Button types](#button-types)\n  - [Validation](#validation)\n    - [Basics](#basics)\n    - [Custom validators](#custom-validators)\n    - [Forcing errors](#forcing-errors)\n  - [Tables](#tables)\n    - [Simple table](#simple-table)\n    - [Column names](#column-names)\n    - [Attributes](#attributes)\n    - [Row selection](#row-selection)\n  - [Assorted topics](#assorted-topics)\n    - [Hiding labels](#hiding-labels)\n    - [Element attributes](#element-attributes)\n    - [Placeholders for empty text boxes](#placeholders-for-empty-text-boxes)\n    - [Using radio buttons](#using-radio-buttons)\n    - [Showing warnings](#showing-warnings)\n    - [Configuration options](#configuration-options)\n  - [Demos](#demos)\n    - [Om](#om)\n    - [Reagent](#reagent)\n    - [Rum](#rum)\n  - [FAQ](#faq)\n    - [How do I submit the form when the user presses ENTER?](#how-do-i-submit-the-form-when-the-user-presses-enter)\n    - [How to affect changes when user clicks a button?](#how-to-affect-changes-when-user-clicks-a-button)\n    - [How to show an operation is in progress?](#how-to-show-an-operation-is-in-progress)\n    - [I'm getting *Each child in an array should have a unique \"key\" prop*. Why?](#im-getting-each-child-in-an-array-should-have-a-unique-key-prop-why)\n    - [Can I bind to local component state (Om-specific)?](#can-i-bind-to-local-component-state-om-specific)\n  - [[API Reference](http://bilus.github.io/reforms/doc/)](#api-referencehttpbilusgithubioreformsdoc)\n  - [TBD](#tbd)\n  - [Credits](#credits)\n  - [License](#license)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Usage\n\n### Getting started with Om\n\nAdd `om-reforms` to `:dependencies` in project.clj:\n\n[![Clojars Project](http://clojars.org/om-reforms/latest-version.svg?2394892384)](http://clojars.org/om-reforms)\n\nMinimal requires (including sablono to render the forms):\n\n```clojure\n(ns hello-world.core\n  (:require [reforms.om :include-macros true :as f]\n            [om.core :as om]\n            [sablono.core :include-macros true :as sablono]))\n```\n\nHere's how you create an Om component with a form with just one text field and a button:\n\n```clojure\n(defn simple-view\n  [data _owner]\n  (om/component\n    (sablono/html\n      (f/form\n        (f/text \"Your name\" data [:name])\n        (f/form-buttons\n           (f/button \"Submit\" #(js/alert (:name @data))))))))\n```\n\nYou render it with `om/build` just like any other component. See [https://github.com/omcljs/om](https://github.com/omcljs/om) for more details.\n\nNote that labels are optional, you can render controls without labels, for instance:\n\n```clojure\n(f/text data [:name] :placeholder \"Enter your name here\")\n```\n\n\n### Getting started with Reagent\n\nAdd `reagent-reforms` to `:dependencies` in project.clj:\n\n[![Clojars Project](http://clojars.org/reagent-reforms/latest-version.svg?2938492384)](http://clojars.org/reagent-reforms)\n\n```clojure\n(ns hello-world.core\n  (:require [reforms.reagent :include-macros true :as f]\n            [reagent.core :refer [atom render-component]))\n```\n\nHere's how you create a Reagent component with a form with just one text field and a button:\n\n```clojure\n(defn simple-view\n  [data]\n  (f/form\n    (f/text \"Your name\" data [:name])\n    (f/form-buttons\n       (f/button \"Submit\" #(js/alert (:name @data))))))\n```\n\nYou render it just like any other component by either mounting it using `render-component` or inside another component using the `[simple-view some-data]` syntax. See [https://github.com/reagent-project/reagent](https://github.com/reagent-project/reagent) for more details.\n\nNote that labels are optional, you can render controls without labels, for instance:\n\n```clojure\n(f/text data [:name] :placeholder \"Enter your name here\")\n```\n\n### Getting started with Rum\n\nAdd `rum-reforms` to `:dependencies` in project.clj:\n\n[![Clojars Project](http://clojars.org/rum-reforms/latest-version.svg?92849238)](http://clojars.org/rum-reforms)\n\n```clojure\n(ns hello-world.core\n  (:require [reforms.rum :include-macros true :as f]\n            [rum.core :include-macros true :as rum])\n```\n\nHere's how you create a Rum component with a form with just one text field and a button:\n\n```clojure\n(rum/defc simple-view \u003c rum/cursored rum/cursored-watch [data horizontal-orientation]\n  [data]\n  (f/form\n    (f/text \"Your name\" data [:name])\n    (f/form-buttons\n       (f/button \"Submit\" #(js/alert (:name @data))))))\n```\n\nYou render it just like any other component by either mounting it using `rum-mount` or inside another component. See [https://github.com/tonsky/rum](https://github.com/tonsky/rum) for more details.\n\nNote that labels are optional, you can render controls without labels, for instance:\n\n```clojure\n(f/text data [:name] :placeholder \"Enter your name here\")\n```\n\n\n### External CSS\n\nThe library does not use Bootstrap JavaScript so just link to bootstrap css from your html page, e.g.:\n\n```html\n\u003clink href=\"https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css\" rel=\"stylesheet\"/\u003e\n```\n\nOptionally, to use Font Awesome icons to use features such as progress spinner, warning icons etc., link to it as well:\n\n```html\n\u003clink href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\" rel=\"stylesheet\"\u003e\n```\n\n\n### Quick tutorial\n\nThe tutorial shows library-agnostic code. For code specific to Om or React, see \"Getting started with ...\" above or the examples.\n\n#### Hello, world!\n\nHere's how you create a form with just one text field and a button:\n\n```clojure\n(f/form\n    (f/text \"Your name\" data [:name])\n    (f/form-buttons\n        (f/button \"Submit\" #(js/alert (:name @data)))))\n```\n\n![Hello world](https://github.com/bilus/reforms/blob/master/doc/images/hello-world.png)\n\nNote that `form` returns a Hiccup-like data structure. The example below, though a bit simplified and scrubbed for clarity, should give you an idea:\n\n```clojure\n[:form [:div {:class \"form-group\"\n              :key \"data-name\"}\n        [:label {:for \"data-name\"\n                 :class \"control-label \"} \"Your name\"]\n        [:input {:value \"My name\"\n                 :type \"text\"\n                 :class \"form-control\"\n                 :id \"data-name\"\n                 :placeholder \"Type your name here\"}]]\n [:div.form-group.form-buttons\n  [:button {:type \"button\"\n            :class \"btn btn-primary\"\n            :onClick #(js/alert (:name @data))} \"Submit\"]]]\n```\n\n#### Data binding\n\nThe controls bind directly to data (Om cursors or Reagent ratoms). For example, as the user types text into the text box below, `data` is automatically updated:\n\n```clojure\n(f/text \"Your name\" data [:name])\n```\n\n\u003cimg src=\"https://github.com/bilus/reforms/blob/master/doc/images/text.png\" width=\"60%\"\u003e\n\n```clojure\n(prn @data) ;; =\u003e {:name \"John Wayne}\n```\n\n\n### Prettying it up\n\n#### Adding a placeholder\n\nYou can add a placeholder shown when the text box is empty using a `:placeholder` option:\n\n```clojure\n(f/text \"Your name\" data [:name] :placeholder \"Enter your name here\")\n```\n\n#### Changing orientation\n\nTo change the orientation use `with-options`:\n\n```clojure\n(f/with-options {:form {:horizontal true}}\n    (f/form\n     (f/text \"Your name\" data [:name] :placeholder \"Enter your name here\")\n     (f/form-buttons\n       (f/button \"Submit\" #(js/alert (:name @data))))))\n```\n\n![Horizontal orientation](https://github.com/bilus/reforms/blob/master/doc/images/hello-world-horizontal.png)\n\n#### Wrapping in a panel\n\nTo wrap the form in a panel use `panel`:\n\n```clojure\n(f/panel\n    \"Hello, world\"\n    (f/form\n      (f/text \"Your name\" data [:name] :placeholder \"Enter your name here\")\n      (f/form-buttons\n        (f/button \"Submit\" #(js/alert (:name @data))))))\n```\n\n![Form wrapped in a panel](https://github.com/bilus/reforms/blob/master/doc/images/hello-world-panel.png)\n\n#### Button types\n\nFinally, let's take make the button clearly a primary one and add a cancel button and, just for the fun of it, a checkbox that toggles the orientation:\n\n```clojure\n(f/form\n  (f/text \"Your name\" data [:name] :placeholder \"Enter your name here\")\n  (f/form-buttons\n    (f/button-primary \"Submit\" #(js/alert (:name @data)))\n    (f/button-default \"Cancel\" #(js/alert \"Cancel!\")))\n  (f/checkbox \"Horizontal form\" data [:orientation-horizontal]))\n```\n\n![Horizontal orientation](https://github.com/bilus/reforms/blob/master/doc/images/hello-world-buttons-hor.png)\n\nClick!\n\n![Vertical orientation](https://github.com/bilus/reforms/blob/master/doc/images/hello-world-buttons-ver.png)\n\nThe complete example: [Om](https://github.com/bilus/om-reforms/blob/master/examples/hello_world/src/hello_world.cljs) ([demo](http://bilus.github.io/reforms/examples/om/hello_world/index.html))\n[Reagent](https://github.com/bilus/reagent-reforms/blob/master/examples/hello_world/src/hello_world.cljs) ([demo](http://bilus.github.io/reforms/examples/reagent/hello_world/index.html)).\n\nFor the list of available controls, see the [API Reference](http://bilus.github.com/reforms/doc/).\n\n### Validation\n\nThe library supports client-side data validation.\n\n#### Basics\n\nTo use validators, `require` `reforms.validation`, use form and form field helpers from this namespace instead of `reforms.core` and use `validate!`:\n\n```clojure\n(ns my-validation-example\n  (:require ... \n            [reforms.validation :include-macros true :as v]))\n```\n\nApart from `form`, the helpers have an identical interface to ones in `reforms.core`.\n\n```clojure\n(v/form                                                           ;; 1\n  ui-state                                                        ;; 2\n  (v/text \"Login\" data [:login])                                  ;; 3\n  (v/password \"Password\" data [:password1]) \n  (v/password \"Confirm password\" data [:password2])\n  (f/form-buttons\n    (f/button-primary \"Sign up\" #(sign-up! data ui-state))))      ;; 4\n```\n\n1. We use `reforms.validation/form`. Note that it takes an extra argument (2).\n2. This is the cursor used to store validation errors. We're using `data` to bind the form fields to and `ui-state` to store validation results in. There's no technical reason we cannot use `data` for this but separating this makes it cleaner.\n3. Again, we use the helpers from `reforms.validation`.\n4. Here we call our function which will perform validation\n\nHere's the sign up function. It shows an alert if data validates:\n\n```clojure\n(defn sign-up!\n  [data ui-state]\n  (when (v/validate!                                                      ;; 1\n           data                                                           ;; 2\n           ui-state                                                       ;; 3\n           (v/present [:login] \"Enter login name\")                        ;; 4\n           (v/equal [:password1] [:password2] \"Passwords do not match\")\n           (v/present [:password1] \"Choose password\")\n           (v/present [:password2] \"Re-enter password\"))\n    (js/alert \"Signed up!\"))\n```\n\n1. `validate!` returns a truthy value if data is valid.\n2. This is data to validate.\n3. Cursor to store validation results.\n4. Validators.\n\nHere's what happens after you click \"Sign up\" while all fields are empty:\n\n\u003cimg src=\"https://github.com/bilus/reforms/blob/master/doc/images/validation-1.png\" width=\"40%\"\u003e\n\nTo satisfy your curiosity, here are the contents of `ui-state`:\n\n```clojure\n{:validation-errors [{:korks #{[:login]}, :error-message \"Enter login name\"} \n                     {:korks #{[:password1]}, :error-message \"Choose password\"} \n                     {:korks #{[:password2]}, :error-message \"Re-enter password\"}]}\n```\n\nA slightly richer example: [Om](https://github.com/bilus/om-reforms/blob/master/examples/validation/src/validation.cljs) ([demo](http://bilus.github.io/reforms/examples/om/validation/index.html))\n[Reagent](https://github.com/bilus/reagent-reforms/blob/master/examples/validation/src/validation.cljs) ([demo](http://bilus.github.io/reforms/examples/reagent/validation/index.html)).\n\nFor the list of available validators, see the [API Reference](http://bilus.github.com/reforms/doc/).\n\n#### Custom validators\n\nA validator is a function that returns a lambda that takes some data and returns `nil` or a validation error. Let's create a custom validation that checks if data is a positive number:\n  \n```clojure\n(defn positive-number?\n  [s]\n  (pos? (js/parseInt s)))\n\n(defn positive-number\n  [korks error-message]                                       ;; 1\n  (fn [cursor]                                                ;; 2\n    (when-not (positive-number? (get-in cursor korks))        ;; 3\n      (v/validation-error [korks] error-message))))           ;; 4\n```\n\n1. The arguments here are up to you. In this example we pass `korks` pointing to data we want to validate and the error message. This is a typical pattern.\n2. The actual function our validator returns takes `cursor`.\n3. Check if it's a positive number.\n4. Build and return an error if it's not.\n\nWhile we're at it, we could make it more readable with the built-in `is-true` validator:\n\n```clojure\n\n(defn positive-number\n  [korks error-message]\n  (v/is-true korks positive-number? error-message))\n```\n\nEither way, you can use your brand new validator like a pro:\n\n```clojure\n(validate! \n    data\n    ui-state\n    (positive-number [:age] \"Age must be a positive number\"))\n```\n\n#### Forcing errors\n\nValidation errors may be forced which comes useful when using external APIs etc. Observe:\n\n```clojure\n(v/validate!\n    customer\n    ui-state\n    (v/force-error [:server-error] \"An error has occurred\"))\n```\n\nYou'd normally call it from an asynchronous error handler, go block etc.\n\nYou can either have a form field show the error if it makes sense by passing its korks to `force-error` or use the `error-alert` helper to render the error:\n\n```clojure\n(v/error-alert [:server-error])\n```\n\nNote that `error-alert` can render any number of custom errors like so:\n\n```clojure\n(v/error-alert [:auth-error] [:twitter-error])\n```\n\n### Tables\n\nStarting with version 0.4.0 Reforms support HTML tables with optional row selection fully stylable using CSS and compatible with Bootstrap table classes\n(if you use Bootstrap in the first place). \n\nFor live example see this [demo](http://bilus.github.io/reforms/examples/reagent/controls/index.html) ([source](https://github.com/bilus/reagent-reforms/tree/master/examples/controls)).\n\n#### Simple table\n\nThis is how you create a simple table, just provide a vector with map per each row:\n\n```clojure\n(t/table [{:name \"Tom\"} {:name \"Jerry\"} {:name \"Mickey\"} {:name \"Minnie\"}])\n```\n\nHere we create just one column.\n\n#### Column names\n\nIt's usually a good idea to give columns human-friendly titles:\n\n```clojure\n(t/table [{:name \"Tom\"} {:name \"Jerry\"} {:name \"Mickey\"} {:name \"Minnie\"}]\n         :columns {:name \"Hero name\"})\n```\n\n#### Attributes\n\nAs with all controls, you can specify optional attributes; they will be applied to the \u003ctable\u003e element (see https://github.com/r0man/sablono#html-attributes):\n\n```clojure\n(t/table {:key \"hero-table\"       ;; Unique React key to avoid warnings.\n          :class \"table-striped\"} ;; Bootstrap table style, see http://getbootstrap.com/css/#tables\n         [{:name \"Tom\"} {:name \"Jerry\"} {:name \"Mickey\"} {:name \"Minnie\"}]\n         :columns {:name \"Hero name\"})\n```\n\n\n#### Row selection\n\nAs an option, you can enable row selection using checkboxes. Current selection is stored in an atom/cursor (as a set of unique row ids).\nThese row ids are provided through a user-defined function, here we use a separate :id column (which isn't visible to the user):\n\n```clojure\n(t/table {:key \"rs-table\"}\n         [{:name \"Tom\" :id 1} {:name \"Jerry\" :id 2} {:name \"Mickey\" :id 3} {:name \"Minnie\" :id 4}]\n         :columns {:name \"Hero name\"}\n         :checkboxes {:selection data\n                      :path      [:selected]\n                      :row-id    :id})\n```\n\nEach selected row gets class \"table-row-selected\" which you can use for styling.\n\nSee the [API Reference](http://bilus.github.io/reforms/doc/reforms.table.html#var-table).\n\n### Assorted topics\n\n#### Hiding labels\n\nStarting with version 0.4.0 labels are optional; for example the text box below will be displayed without a label:\n\n```clojure\n(f/text data [:name])\n```\n\n#### Element attributes\n\nEach form helper accepts React attributes as the first argument. These attributes will be handed over to React (see https://github.com/r0man/sablono#html-attributes)\n\n```clojure\n(text {:key \"name-1\"} \"Name\" user [:name])\n```\n\nAttributes are optional, this form will work as well.\n\n```clojure\n(text \"Name\" user [:name])\n```\n\n#### Placeholders for empty text boxes\n\nYou can add a placeholder shown when the text box is empty using a `:placeholder` option:\n\n```clojure\n(f/text \"Your name\" data [:name] :placeholder \"Enter your name here\")\n```\n\nIt also works for `textarea` and other controls based on `html5-input` such as `password`, `datetime-local`, `email` and others. \n\n#### Using radio buttons\n\nWhen using radio buttons remember to provide a value, for instance:\n\n```clojure\n(f/form\n  (f/radio \"Data\" app-state [:current-view] :data)\n  (f/radio \"Groups\" app-state [:current-view] :groups))\n```\n\n#### Showing warnings\n\nIn addition to validation proper, `text`, `password` and other controls based on `html5-input` support warnings:\n  \n```clojure\n(text \"City\" [:city] :warn-fn #(when-not (= \"Kansas\" %) \"We're not in Kansas anymore\")\n```\n\n\u003cimg src=\"https://github.com/bilus/reforms/blob/master/doc/images/warning.png\" width=\"70%\"\u003e\n\nNote that by default a Font Awesome icon is used to show the warning icon. You can override this using `(set-options! [:icon-warning] \"...\")`.\n  \n#### Configuration options\n\nYou can configure global options using `set-options!`. See [this](http://bilus.github.io/reforms/doc/reforms.core.options.html) for details.\n\nHere's a quick example:\n\n```clojure\n;; Set background of every form to red color.\n(set-options! {:form {:attrs {:style {:background-color \"red\"}}}})\n```\n\n### Demos\n\n#### Om\n\n- Hello world [source](https://github.com/bilus/om-reforms/tree/master/examples/hello_world) [demo](http://bilus.github.io/reforms/examples/om/hello_world/index.html)\n- Dynamic form with customizations [source](https://github.com/bilus/om-reforms/tree/master/examples/simple) [demo](http://bilus.github.io/reforms/examples/om/simple/index.html)\n- Available controls [source](https://github.com/bilus/om-reforms/tree/master/examples/controls) [demo](http://bilus.github.io/reforms/examples/om/controls/index.html)\n- Validation [source](https://github.com/bilus/om-reforms/tree/master/examples/validation) [demo](http://bilus.github.io/reforms/examples/om/validation/index.html)\n- Background operations [source](https://github.com/bilus/om-reforms/tree/master/examples/validation) [demo](http://bilus.github.io/reforms/om/examples/progress/index.html)\n\n#### Reagent\n\n- Hello world [source](https://github.com/bilus/reagent-reforms/tree/master/examples/hello_world) [demo](http://bilus.github.io/reforms/examples/reagent/hello_world/index.html)\n- Dynamic form with customizations [source](https://github.com/bilus/reagent-reforms/tree/master/examples/simple) [demo](http://bilus.github.io/reforms/examples/reagent/simple/index.html)\n- Available controls [source](https://github.com/bilus/reagent-reforms/tree/master/examples/controls) [demo](http://bilus.github.io/reforms/examples/reagent/controls/index.html)\n- Validation [source](https://github.com/bilus/reagent-reforms/tree/master/examples/validation) [demo](http://bilus.github.io/reforms/examples/reagent/validation/index.html)\n- Background operations [source](https://github.com/bilus/reagent-reforms/tree/master/examples/validation) [demo](http://bilus.github.io/reforms/examples/reagent/progress/index.html)\n\n#### Rum\n\n- Hello world [source](https://github.com/bilus/rum-reforms/tree/master/examples/hello_world) [demo](http://bilus.github.io/reforms/examples/rum/hello_world/index.html)\n- Dynamic form with customizations [source](https://github.com/bilus/rum-reforms/tree/master/examples/simple) [demo](http://bilus.github.io/reforms/examples/rum/simple/index.html)\n- Available controls [source](https://github.com/bilus/rum-reforms/tree/master/examples/controls) [demo](http://bilus.github.io/reforms/examples/rum/controls/index.html)\n- Validation [source](https://github.com/bilus/rum-reforms/tree/master/examples/validation) [demo](http://bilus.github.io/reforms/examples/rum/validation/index.html)\n- Background operations [source](https://github.com/bilus/rum-reforms/tree/master/examples/validation) [demo](http://bilus.github.io/reforms/examples/rum/progress/index.html)\n\n### FAQ\n#### How do I submit the form when the user presses ENTER?\n\nUse the `:on-submit` attribute and pass the same function you use to handle clicks:\n\n```clojure\n(form\n    {:on-submit #(do-something customer)}\n    (text \"First name\" \"Enter first name\" customer [:first])\n    ...\n    (f/form-buttons\n      (f/button-primary \"Save\" #(do-something customer))))\n```\n\n**Note:** If `:on-submit` is set, the resulting form will include a hidden submit button. \n\n#### How to affect changes when user clicks a button?\n\nBecause form helpers bind to data, everything user types in is automatically synchronized. If this isn't what you need, create a copy of data before handing it over to the form and then copy it back on save.\n\n#### How to show an operation is in progress?\n\nButtons and most form helpers accept an `:in-progress` option you can use like this:\n\n```clojure\n(button \"Start\" #(...) :in-progress true)\n```\n\nIn addition, in case of buttons it's usually a good idea to disable them:\n\n```clojure\n(button \"Start\" #(...) :in-progress true :disabled true)\n```\n\n\u003cimg src=\"https://github.com/bilus/reforms/blob/master/doc/images/progress.png\" width=\"85\"\u003e\n\nSee this example: [Om](https://github.com/bilus/om-reforms/tree/master/examples/progress/) ([demo](http://bilus.github.io/reforms/examples/om/progress/index.html))\n[Reagent](https://github.com/bilus/reagent-reforms/tree/master/examples/progress/) ([demo](http://bilus.github.io/reforms/examples/reagent/progress/index.html))\n[Rum](https://github.com/bilus/rum-reforms/tree/master/examples/progress/) ([demo](http://bilus.github.io/reforms/examples/rum/progress/index.html))\n\n#### I'm getting *Each child in an array should have a unique \"key\" prop*. Why?\n\nIf you use Om, it's likely the warning is sabl0no-related (see [this](https://github.com/r0man/sablono/issues/57)).\n\nIn your own code avoid passing child elements as a sequence whenever possible:\n\n```clojure\n[:ul\n  (for [item items]\n    [:li item])]\n```\n\nwith:\n\n```clojure\n(into\n  [:ul]\n  (for [item items]\n    [:li item]))\n```\n\nIf you need to pass a sequence, use attributes to set React key. For example, use code similar to this:\n\n```clojure\n(let [items [{:title \"foo\" :id 1} {:title \"bar\" :id 2}]]\n  [:ul\n    (for [{:keys [title id]} items]\n      [:li {:key id} title])])\n```\n\nOn the other hand, if you do find a bug in Reforms, please do report it [here](https://github.com/bilus/reforms/issues).\n\n#### Can I bind to local component state (Om-specific)?\n\n\nYes, there's experimental support for this, just remember to use `render-state` instead of `render`:\n\n```clojure\n(defn simple-view\n  [_ owner]\n  (reify\n    om/IRenderState\n    (render-state [_ _]\n      (f/text \"Your name\" owner [:name] :placeholder \"Type your name here\"))))\n```\n\nYou can also store validation data in local state which may be useful even if you store the actual data in an atom. \n\nA slightly more complete example: [source](https://github.com/bilus/om-reforms/tree/master/examples/local_state/) [demo](http://bilus.github.io/reforms/examples/om/local_state/index.html)\n\n** This is an experimental feature. Please report any bugs. **\n\n\n### [API Reference](http://bilus.github.io/reforms/doc/)\n\n\nPlease feel free to tweet me @martinbilski or drop me an email: gyamtso at gmail dot com.\n\n### TBD\n\n- Keep Readme short, move most of it to wiki.\n- Contact library authors.\n- Add tabs. Update 'controls' example. Blog post.\n- Port tests.\n\n### Credits\n\n[Aspasia Beneti](https://github.com/aspasia) is the author and maintainer of [Rum bindings](https://github.com/aspasia/rum-reforms) for Reforms.\n\n### License\n\nCopyright © 2015 Designed.ly, Marcin Bilski\n\nThe use and distribution terms for this software are covered by the\nEclipse Public License which can be found in the file LICENSE at the root of this distribution.\nBy using this software in any fashion, you are agreeing to be bound by the terms of this license.\nYou must not remove this notice, or any other, from this software.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbilus%2Freforms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbilus%2Freforms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbilus%2Freforms/lists"}