esc

Type to search...

Form Config Map

The first argument to fork/form is a config map. Every key is optional except :on-submit if you want submission handling. Here's the full set:

Prop Type Default Description
:initial-values map Pre-populates form fields. Keys must match input :name attributes. e.g. {"name" "John", "email" ""}
:initial-touched map Pre-populates fields AND marks them as touched. Useful for edit forms where you want validation errors visible immediately.
:path keyword | vector Where to store global state in re-frame app-db. Can be a keyword (:form) or a vector ([:forms :login]). Only relevant for fork.re-frame.
:form-id string HTML id for the form element. If omitted, a random id is generated and available via the :form-id key in props.
:keywordize-keys boolean When true, field names are treated as keywords instead of strings. Use normalize-name to convert keyword input names for the DOM.
:prevent-default? boolean Prevents the browser's default form submission behavior. Almost always true for SPA forms.
:clean-on-unmount? boolean Resets the re-frame app-db state at :path when the component unmounts. Only applies to fork.re-frame.
:validation function A function that receives the values map and returns errors. Any validation library works. Fork blocks submission while errors exist.
:on-submit function Called on valid submission. Receives a map with :state, :path, :values, :dirty, and :reset.
:component-did-mount function Lifecycle hook called after mount. Receives a map of handlers: set-touched, set-untouched, set-values, disable, enable, disabled?, handle-change, handle-blur, send-server-request.
:state ratom Provide your own ratom for form state. Useful when you need to access form state from outside the form component.
:props map Pass arbitrary data through to your form component. Accessible via the :props key in the component's argument map.

Reagent vs Re-frame

The APIs are identical. The difference is where server-related state lives:

reagent-vs-reframe.cljs
;; Reagent: everything in a local ratom
(ns app.core
  (:require [fork.reagent :as fork]))

;; State helpers operate on the ratom directly
(swap! state fork/set-submitting path true)

;; Re-frame: server state lives in app-db
(ns app.core
  (:require [fork.re-frame :as fork]))

;; State helpers operate on the db inside events
(rf/reg-event-db
 :my-event
 (fn [db [_ path]]
   (fork/set-submitting db path true)))

Keyword Keys

By default, Fork uses string keys for field names. If you prefer keywords (including namespaced keywords), enable :keywordize-keys and use normalize-name for DOM attributes:

keyword-keys.cljs
[fork/form {:keywordize-keys true
            :initial-values {:user/name "John"
                             :user/email ""}}
 (fn [{:keys [values handle-change handle-blur normalize-name]}]
   [:div
    [:input
     {:name (normalize-name :user/name)
      :value (values :user/name)
      :on-change handle-change
      :on-blur handle-blur}]
    [:input
     {:name (normalize-name :user/email)
      :value (values :user/email)
      :on-change handle-change
      :on-blur handle-blur}]])]

normalize-name converts :user/name to "user/name" for the DOM name attribute. When :keywordize-keys is not set, it returns the value unchanged.

Custom State

Pass your own ratom via :state to access form state from outside the form component. Fork merges its initial state into your atom, preserving any existing keys:

custom-state.cljs
(def my-state (r/atom {:custom-key "preserved"}))

[fork/form {:state my-state
            :initial-values {"name" ""}}
 (fn [{:keys [values handle-change]}]
   ;; my-state now contains both :custom-key and Fork's :values, :touched, etc.
   [:input
    {:name "name"
     :value (values "name")
     :on-change handle-change}])]

;; Outside the form, you can read:
(:values @my-state) ;; => {"name" "current-value"}

Passing Props

Use :props to pass data through to your form component without polluting the config:

passing-props.cljs
(defn my-form
  [{:keys [props values handle-change handle-blur]}]
  [:div
   [:h2 (:title props)]
   [:input
    {:name "input"
     :value (values "input")
     :on-change handle-change
     :on-blur handle-blur}]])

(defn app []
  [fork/form {:props {:title "Registration Form"}
              :initial-values {"input" ""}}
   my-form])

Next Steps