Labeled Checkboxes


Follow along in the online editor.


Your app will probably have some options people can mess with. If something happens, should you send them an email notification? If they come across a video, should it start playing by itself? That kind of thing. So you will need to create some HTML like this:

  1. <fieldset>
  2. <label><input type="checkbox">Email Notifications</label>
  3. <label><input type="checkbox">Video Autoplay</label>
  4. <label><input type="checkbox">Use Location</label>
  5. </fieldset>

That will let people toggle the checkboxes, and using <label> means they get a much bigger area they can click on. Let’s write an Elm program that manages all this interaction! As always, we will take a guess at our Model. We know we need to track the user’s settings so we will put them in our model:

  1. type alias Model =
  2. { notifications : Bool
  3. , autoplay : Bool
  4. , location : Bool
  5. }

From there, we will want to figure out our messages and update function. Maybe something like this:

  1. type Msg
  2. = ToggleNotifications
  3. | ToggleAutoplay
  4. | ToggleLocation
  5. update : Msg -> Model -> Model
  6. update msg model =
  7. case msg of
  8. ToggleNotifications ->
  9. { model | notifications = not model.notifications }
  10. ToggleAutoplay ->
  11. { model | autoplay = not model.autoplay }
  12. ToggleLocation ->
  13. { model | location = not model.location }

That seems fine. Now to create our view!

  1. view : Model -> Html Msg
  2. view model =
  3. fieldset []
  4. [ label []
  5. [ input [ type_ "checkbox", onClick ToggleNotifications ] []
  6. , text "Email Notifications"
  7. ]
  8. , label []
  9. [ input [ type_ "checkbox", onClick ToggleAutoplay ] []
  10. , text "Video Autoplay"
  11. ]
  12. , label []
  13. [ input [ type_ "checkbox", onClick ToggleLocation ] []
  14. , text "Use Location"
  15. ]
  16. ]

This is not too crazy, but we are repeating ourselves a bit. How can we make our view function nicer? If you are coming from JavaScript, your first instinct is probably that we should make a “labeled checkbox component” but it is easier to just create a helper function! Here is the view function with a checkbox helper function:

  1. view : Model -> Html Msg
  2. view model =
  3. fieldset []
  4. [ checkbox ToggleNotifications "Email Notifications"
  5. , checkbox ToggleAutoplay "Video Autoplay"
  6. , checkbox ToggleLocation "Use Location"
  7. ]
  8. checkbox : msg -> String -> Html msg
  9. checkbox msg name =
  10. label []
  11. [ input [ type_ "checkbox", onClick msg ] []
  12. , text name
  13. ]

Now we have a highly configurable checkbox function. It takes two arguments to configure how it works: the message it produces on clicks and some text to show next to the checkbox. Now if we decide we want all checkboxes to have a certain class, we just add it in the checkbox function and it shows up everywhere! This is the essense of reusable views in Elm. Create helper functions!

Comparing Reusable Views to Reusable Components

We now have enough information to do a simple comparison of these approaches. Reusable views have a few major advantages over components:

  • It is just functions. We are not doing anything special here. Functions have all the power we need, and they are very simple to create. It is the most basic building block of Elm!

  • No parent-child communication. If we had made a “checkbox component” we would have to figure out how to synchronize the state in the checkbox component with our overall model. “That checkbox says notifications are on, but the model says they are off!” Maybe we need a Flux store now? By using functions instead, we are able to have reuse in our view without disrupting our Model or update. They work exactly the same as before, no need to touch them!

This means we can always create reusable view code without changing our overall architecture or introducing any fancy ideas. Just write smaller functions. That sounds nice, but let’s see some more examples to make sure it is true!