What's Your Favorite Form Lib?

What’s your favorite library for working with forms (and validating them) and why? Or is it more common to just roll-your-own solution? I’m looking at etaque/elm-form and hecrj/composable-form at the moment because they have the most GitHub stars among the libs I’ve seen, but I’m sure there are other good options. I don’t have time to vet a bunch of them personally, but would really like to have some confidence that I’m not going to regret my choice down the road.

To that end, would you mind sharing what your favorite form library is, and perhaps why? If someone has already mentioned your favorite, just :heart: their comment to keep things tidy.

1 Like

In one of my applications I use a custom implementation of the idea described here: https://arow.info/posts/2019/form-decoding/

I like this strategy because it separates the form definition (view code) from the form validation which in my opinion should be two separate things. It also has the flexibility to show errors either next to the inputs or at the top of the form, or both. Whatever makes sense for the form. My custom implementation allows me to generate types from the validation/decoding that I can feed directly into the API generated by elm-graphql. This means I don’t have to write any additional code for converting the validated data into JSON or something else after the form decoder completes its validation.

So basically I use elm-graphql to select the data directly into the a record of string values (even if I want the user to provide a number - since that’s the appropriate data type for HTML input) then have a form decoder that decodes directly into the input records expected by the GraphQL API.

Additionally I write Html.input [Evt.onInput (\newName -> { person | name = newName})] [] instead of Html.input [Evt.onInput SetName] [] which results in an Html Person type instead of Html Msg. Then at the top of the form I use Html.map SetPerson to convert it to Html Msg. This lets me avoid 50+ lines of uninteresting case statements in the update method. I’ve found this works well as long as you keep the Html Person type very targeted. Don’t try composing nested records or nested lists unless it is absolutely necessary. I’ve found composing like that typically gives very overly complicated code.

Finally, I took the above ideas and built a custom Form module specific to my application. So my typical form code on most pages looks like:

viewForm : List FormError -> FormModel -> Html Msg
viewForm =
  Form.view SetPerson
    [ Form.label "First Name"
    , Form.text Focus.firstName
    , Form.errors [(FirstNameRequired, "First Name is Required")]
    , Form.label "Last Name"
    , Form.text Focus.lastName
    , Form.errors [(LastNameRequired, "Last Name is Required")]
    , Form.label "Age"
    , Form.text Focus.age
    , Form.errors [(AgeNotPositive, "Age Must be Positive"), (AgeNotNumeric, "Age Must be a Number")]
    ]

decodePerson : FormDecoder Api.InputObject.Person FormError
decodePerson =
  Form.succed Api.InputObject.Person
    |> Form.requiredString FirstNameRequired .firstName
    |> Form.requiredString LastNameRequired .lastName
    |> Form.positive AgeNotPositive (Form.requiredInt AgeNotNumeric .age)
5 Likes

I am kind of in the “roll your own” camp.

I think its kind of hard to find a one-size-fits-all solution to forms.

A lot of similar and related things fall into the category of “forms”, so its hard to know exactly if any form package is addressing your particular form needs. There are a number of questions you have to ask yourself about what UX you want your project to have that will greatly change the answer to how your form should be coded. For example:

  • Is your form purely a UI thing?
  • Does “validation” for you, include constructing valid data -> Result error data, or just checking if data is valid -> Bool?
  • What are you validating, specific fields or the entire form? Do the fields depend on each other?
  • When do they validate? On blur? On interaction? When you click submit? Will different fields validate differently?
  • Are the fields of your form dynamic?
1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.