esc

Type to search...

React Interop

Fork doesn't render anything, which means it works with any component that accepts value and change handler props. This includes JavaScript React components accessed via ClojureScript interop. The pattern is always the same: read the current value from values, write updates via set-values.

This example integrates react-dates (both single date and date range pickers) into a Fork form alongside a standard text input. The datepicker components are plain Reagent wrappers around the JavaScript library.

Single Date Picker

The single date picker stores a Moment.js object as the field value. Focus state is managed through Fork's state ratom directly, keeping the datepicker's open/closed state alongside the form data:

datepicker.cljs
(defn react-dates-single-date-picker
  [k {:keys [values state set-values]}]
  [:> js/ReactDates.SingleDatePicker
   {:date (get values k)
    :display-format "DD MMM YYYY"
    :on-focus-change
    (fn [e]
      (swap! state #(assoc-in % [:focus k] (.-focused e))))
    :focused (get-in @state [:focus k])
    :on-date-change #(set-values {k %})}])

The key insight: set-values accepts any value type, not just strings. The Moment.js date object goes straight into Fork's state and comes back out via values.

Date Range Picker

The range picker works the same way, except the value is a map with :startDate and :endDate keys:

datepicker.cljs
(defn react-dates-date-range-picker
  [k {:keys [values state set-values]}]
  [:> js/ReactDates.DateRangePicker
   {:start-date (get-in values [k :startDate])
    :end-date (get-in values [k :endDate])
    :display-format "DD MMM YYYY"
    :on-focus-change
    (fn [e]
      (swap! state #(assoc-in % [:focus k] e)))
    :focused-input (get-in @state [:focus k])
    :on-dates-change
    #(set-values {k (js->clj % :keywordize-keys true)})}])

Full Form

Both datepickers alongside a standard text input in one form. :keywordize-keys true is enabled so all field names are keywords, and normalize-name converts them for DOM attributes:

datepicker.cljs
(ns examples.datepicker
  (:require
   ;; for CSS use:
   ;; https://unpkg.com/react-dates@16.3.2/lib/css/_datepicker.css
   [cljsjs.react-dates]
   [cljs.pprint :as pprint]
   [fork.reagent :as fork]))

(defn view []
  [fork/form
   {:keywordize-keys true
    :prevent-default? true
    :on-submit #(js/alert (:values %))
    :initial-values
    {:dummy/input "Just an input"
     :single-date-picker (js/moment)
     :date-range-picker {:startDate (js/moment)}}}
   (fn [{:keys [state form-id values normalize-name
                handle-change handle-blur handle-submit]
         :as props}]
     [:div
      [:pre (with-out-str (pprint/pprint @state))]
      [:form
       {:id form-id
        :on-submit handle-submit}
       [:div
        [:label "Dummy input"]
        [:input
         {:type "text"
          :name (normalize-name :dummy/input)
          :value (:dummy/input values)
          :on-change handle-change
          :on-blur handle-blur}]]
       [:br]
       [react-dates-single-date-picker
        :single-date-picker props]
       [:br]
       [react-dates-date-range-picker
        :date-range-picker props]
       [:br]
       [:button {:type "submit"} "Submit!"]]])])