As its name suggests, Fable.Form allows you to create forms in your Fable application. It is a collection of Fable libraries, of which you can use all or only a subset:
- Fable.Form, which contains base types without details of any particular field types.
- Fable.Form.Simple, which contains support for a few different field types such as text input, checkboxes etc.
- Fable.Form.Simple.Bulma, which uses Bulma to render the forms defined using Fable.Form.Simple.
The advantage of the split is that it is possible to create F# libraries that use different CSS libraries for rendering, such as Fable.Form.Simple.MaterialUI, or ones that support different field types than Fable.Form.Simple.
The docs state that Fable.Form allows you to build forms that are composable, type safe, scalable, terse and modular. These are intriguing claims, and there are plenty of examples, which are worth exploring. The examples are so good that I'll just highlight one of them here rather than create my own 🙂
Basic example
Suppose you have an email address type and a corresponding function that validates that a string can make a valid email address:
module EmailAddress
type T =
private EmailAddress of string
...
let tryParse (text : string) =
if text.Contains("@") then
Ok (EmailAddress text)
else
Error "The e-mail address must contain a '@' symbol"
You can use the parsing function in your Fable.Form definition, and have the form use the underlying type when dispatching Elmish messages:
type Values =
{
Email : string
Password : string
RememberMe : bool
}
type Msg =
| FormChanged of Model
| LogIn of EmailAddress.T * string * bool
let init () = ...
let update (msg : Msg) (model : Model) = ...
match msg with
| FormChanged newModel -> ...
| LogIn (_email, _password, _rememberMe) -> ...
let form : Form.Form<Values, Msg, _> =
let emailField =
Form.textField
{
Parser =
EmailAddress.tryParse
Value =
fun values -> values.Email
Update =
fun newValue values ->
{ values with Email = newValue }
Error =
fun _ -> None
Attributes =
{
Label = "Email"
Placeholder = "some@email.com"
HtmlAttributes = [
prop.autoComplete "email"
]
}
}
let passwordField = ...
let rememberMe = ...
let onSubmit =
fun email password rememberMe ->
LogIn (email, password, rememberMe)
Form.succeed onSubmit
|> Form.append emailField
|> Form.append passwordField
|> Form.append rememberMe
let view (model : Model) (dispatch : Dispatch<Msg>) =
Form.View.asHtml
{
Dispatch = dispatch
OnChange = FormChanged
Action = Form.View.Action.SubmitOnly "Sign in"
Validation = Form.View.ValidateOnSubmit
}
form
model
With the form wired up as above, validation is taken care of for you:
As promised, you can also compose forms:
Wrap up
That was just a quick post to give you a flavour of Fable.Form. I'm impressed by its clean interface, and it seems to me that it delivers on its promises of being composable, type safe, scalable, terse and modular. In a future post I'll show how to use Fable.Form in a SAFE app!
Thanks to Maxime and all Fable.Form contributors for making this library available!