Creating HTML Elements and Using Libraries in Elm

We mentioned in our last episode that syntax in Elm is something people don't understand at first and consequently frustrates many beginners. In this episode we will create some elements, interact more with HTML and add a Styling library. If you're a beginner in Elm, this tutorial is for you!

Creating Elements

We will use the previous episode’s code and improve it with some CSS.

In our previous code we have already interacted with the DOM. Let's take a look:

view model =
    div []
        [ button [ onClick Decrement ] [ text "-" ]
        , div [] [ text (toString model) ]
        , div [] [ text (checkNumber model.quantity) ]
        , button [ onClick Increment ] [ text "+" ]
        ]

Let's see what is happening here. If we check the Elm source code, we will see the following function to represent a div:

{-| Represents a generic container with no special meaning. -}
div : List Attribute -> List Html -> Html
div =
  node "div"

The div function receives a List of Attributes and a List of HTML elements and it returns Html. So, every time we do a: div [] [] you will know what it really does.

Using Libraries

We are going to use a Bootstrap library for Elm – a UI library that is a wrapper for Bootstrap.

Here are several other Styling libraries Josh has explained:

elm package install rundis/elm-bootstrap

This command will install elm-bootstrap in our app, as we can see in our elm-package.json:

    "dependencies": {
        "elm-lang/core": "5.1.1 <= v < 6.0.0",
        "elm-lang/html": "2.0.0 <= v < 3.0.0",
        "rundis/elm-bootstrap": "2.0.0 <= v < 3.0.0"
    },

This gives us access to all elements from this library, which you can see on its GitHub.

We will use Card and Button for our simple app.

As we can see in the documentation, we need to create a container to start working with elm-bootstrap. Let's change our main function and do that:

view : Model -> Html Msg
view model =
    Grid.container []
        [ CDN.stylesheet
        , CDN.fontAwesome
        , mainContent model
        ]

We will create a function that will return only HTML for us, it's called mainContent. In this function, we will have the two buttons we had before and another function for the how it works section.

mainContent model =
    div []
        [ Button.button [ Button.onClick Increment, Button.success, Button.large ]
            [ text "+"
            ]
        , div [] [ text (toString model) ]
        , Button.button
            [ Button.onClick Decrement
            , Button.danger
            , Button.large
            ]
            [ text "-"
            ]
        , howItWorksSection
        ]

I think now you're more familiar with the many [ ] (like in the div function). Let's look closer at the Button function to try to understand better what we did.

Let's see it:

{-| Create a button
    Button.button [ Button.primary ] [ text "Primary" ]
* `options` List of styling options
* `children` List of child elements
-}
button :
    List (Option msg)
    -> List (Html.Html msg)
    -> Html.Html msg
button options children =
    Html.button
        (ButtonInternal.buttonAttributes options)
        children

The function Button.button receives two parameters, a list of options and a list of child elements. Let's look at ourhowItWorksSection will be.

howItWorksSection =
    div []
        [ h2 [] [ text "How it works" ]
        , div []
            [ myCard "We have created a simple app"
            , myCard "We have add elm-bootstrap"
            , myCard "We have created some functions to render the HTML"
            ]
        , a [ href "http://elm-lang.org/" ] [ text "This page was made in Elm" ]
        ]

We have opened a div, used h2 and created a myCard function:

The function myCard receives the content and we are using the Card from elm-bootstrap. We are passing the content to this function and we are rendering it as text.

myCard content =
    Card.config [ Card.outlinePrimary ]
        |> Card.block []
            [ Card.text [] [ text content ] ]
        |> Card.view

Let's use Elm Reactor and see what the page looks like.

elm-reactor

We can see we have a styled button for increment/decrement and some cards explaining how it works.

Our complete code will be:

module Main exposing (..)

import Html exposing (Html, button, div, text, h2, a)
import Html.Attributes exposing (..)
import Bootstrap.Button as Button
import Bootstrap.CDN as CDN
import Bootstrap.Grid as Grid
import Bootstrap.Card as Card


main =
    Html.beginnerProgram { model = model, view = view, update = update }



-- MODEL


type alias Model =
    Int


model : Model
model =
    0



-- UPDATE


type Msg
    = Increment
    | Decrement


update : Msg -> Model -> Model
update msg model =
    case msg of
        Increment ->
            model + 1

        Decrement ->
            model - 1



-- VIEW


mainContent model =
    div []
        [ Button.button [ Button.onClick Increment, Button.success, Button.large ]
            [ text "+"
            ]
        , div [] [ text (toString model) ]
        , Button.button
            [ Button.onClick Decrement
            , Button.danger
            , Button.large
            ]
            [ text "-"
            ]
        , howItWorksSection
        ]


myCard content =
    Card.config [ Card.outlinePrimary ]
        |> Card.block []
            [ Card.text [] [ text content ] ]
        |> Card.view


howItWorksSection =
    div []
        [ h2 [] [ text "How it works" ]
        , div []
            [ myCard "We have created a simple app"
            , myCard "We have add elm-bootstrap"
            , myCard "We have created some functions to render the HTML"
            ]
        , a [ href "http://elm-lang.org/" ] [ text "This page was made with Elm" ]
        ]


view : Model -> Html Msg
view model =
    Grid.container []
        [ CDN.stylesheet
        , CDN.fontAwesome
        , mainContent model
        ]

If you want to keep learning Elm, check out some DailyDrip videos.

Interesting Elm Videos