Radio Buttons


    Follow along in the online editor.


    Just like in the checkbox example from the previous page, this will let people choose the one they want, and using means they get a much bigger area they can click on. Like always, we start with our Model. This one is kind of interesting because we can use to make it very reliable!

    1. type alias Model =
    2. { fontSize : FontSize
    3. , content : String
    4. }
    5. type FontSize = Small | Medium | Large

    This means there are exactly three possible font sizes: Small, Medium, and Large. It is impossible to have any other value in our fontSize field. If you are coming from JavaScript, you know their alternative is to use strings or numbers and just hope that there is never a typo or mistake. You could use values like that in Elm, but why open yourself up to bugs for no reason?!

    Alright, now we need to update our model. In this case we just want to switch between font sizes as the user toggles the radio buttons:

    1. view : Model -> Html Msg
    2. view model =
    3. div []
    4. [ fieldset []
    5. [ label []
    6. [ input [ type_ "radio", onClick (SwitchTo Small) ] []
    7. ]
    8. , label []
    9. , text "Medium"
    10. ]
    11. , label []
    12. [ input [ type_ "radio", onClick (SwitchTo Large) ] []
    13. , text "Large"
    14. ]
    15. ]
    16. , section [] [ text model.content ]
    17. ]

    That is kind of a mess! The best thing to do is to start making helper functions (not components!). We see some repetition in the radio buttons, so we will start there.

    Our view function is quite a bit easier to read now. Great!

    If that is the only chunk of radio buttons on your page, you are done. But perhaps you have a couple sets of radio buttons. For example, this guide not only lets you set font size, but also color scheme and whether you use a serif or sans-serif font. Each of those can be implemented as a set of radio buttons, so we could do a bit more refactoring, like this:

    1. view : Model -> Html Msg
    2. view model =
    3. div []
    4. [ viewPicker
    5. [ ("Small", SwitchTo Small)
    6. , ("Medium", SwitchTo Medium)
    7. ]
    8. ]
    9. viewPicker : List (String, msg) -> Html msg
    10. viewPicker options =
    11. fieldset [] (List.map radio options)
    12. radio : (String, msg) -> Html msg
    13. radio (name, msg) =
    14. label []
    15. [ input [ type_ "radio", onClick msg ] []
    16. , text name
    17. ]

    So if we want to let users choose a color scheme or toggle serifs, the view can reuse viewPicker for each case. If we do that, we may want to add additional arguments to the viewPicker function. If we want to be able to set a class on each <fieldset>, we could add an argument like this:

    1. viewPicker : List (Attribute msg) -> List (String, msg) -> Html msg
    2. fieldset attributes (List.map radio options)

    And if we wanted even MORE flexibility, we could let people pass in attributes for each radio button too! There is really no end to what can be configured. You just add a bit more information to an argument.

    In this case, we saw quite a few ways to write the same code. But which way is the right way to do it? A good rule to pick an API is choose the absolute simplest thing that does everything you need. Here are some scenarios that test this rule:

    1. There is the only radio button thing on your page. In that case, just make them! Do not worry about making a highly configurable and reusable function for radio buttons. Refactoring is easy in Elm, so wait for a legitimate need before doing that work!

    2. There are a couple radio button things on your page, all with the same styling. That is how the options on this guide look. This is a great case for sharing a view function. You may not even need to change any classes or add any custom attributes. If you do not need that, do not design for it! It is easy to add later.

    Point is, there is no magic recipe here. The answer will depend on the particulars of your application, and you should always try to find the simplest approach. Sometimes that means sharing code. Sometimes it means writing similar code. It takes practice and experience to get good at this, so do not be afraid to experiment to find simpler ways!