HTML Form Fields: Readonly vs. Disabled

I've been tinkering with the form element once again as web developers often do and lately, I've been using the FormData to parse the values and validate the collected form data with Malli. I often default to using disabled="true" when sketching the forms and I want to block the user from altering a static value, but this week, it hit me that read-only and disabled HTML attributes have different implications.

Here's a simple example of what I mean.

(defnc app []
  (d/form
   {:id "form"}
   (d/input {:name (str :static)
             :default-value "non-mutable"})
   (d/fieldset
    {:name "demo"}
    (d/div
     (d/label "one")
     (d/input {:name (str [:data :value-1])
               :default-value "value-one"}))
    (d/div
     (d/label "two")
     (d/input {:name (str [:data :value-2])
               :default-value "value-two"})))))

And here's a naive form parser.

  (defn naive-form-parser [^js/HTMLFormElement form]
    (reduce
     (fn [form-data [k v]]
       (let [path (edn/read-string k)]
         (if (sequential? path)
           (assoc-in form-data path v)
           (assoc form-data path v))))
     {}
     (for [entry (.entries (js/FormData. form))]
       entry)))

  (naive-form-parser form)
;; => 
{:static "non-mutable", 
 :data {:value-1 "value-one", 
        :value-2 "value-two"}}

Now if we set the static field as disabled

(d/input {:name "static" 
          :disabled true
          :default-value "non-mutable"})
;; ...

(naive-form-parser form)
;; => 
{:data {:value-1 "value-one", 
        :value-2 "value-two"}}

The disabled=true makes the input field "invisible" to the FormData, but when using the readonly=true it will be visible.

(d/input {:name "static" 
          :read-only true
          :default-value "non-mutable"})
;; ...

(naive-form-parser form)
;; => 
{:static "non-mutable", 
 :data {:value-1 "value-one", 
        :value-2 "value-two"}}

And of course, this is pretty clear if you read through the docs:

The Boolean disabled attribute, when present, makes the element not mutable, focusable, or even submitted with the form. The user can neither edit nor focus on the control, nor its form control descendants.

https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled

These details can be easy to forget when working with React and other libraries. There's nothing new in this post. I just thought that this was curious since I don't remember paying attention before to this small detail.

If you were wondering the code examples are in Helix.