# Are there any common patters for dealing with conditionally including markup?

**URL:** <https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242>\
**Category:** Learn\
**Created:** [February 29, 2020, 11:05pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242 "2020-02-29T23:05:44Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![ursi](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ursi/32/3166_2.png) [@ursi](https://discourse.elm-lang.org/u/ursi)\
**Post date:** [February 29, 2020, 11:05pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/1 "2020-02-29T23:05:44Z")

</div>

I’m rather new to Elm, and while I am I’m absolutely loving it, this was definitely a pain point for me.  
The standard way to conditionally include an HTML element, as far as I can tell is

```auto
div []
        [ element1
        , if condition then
            element2

          else
            text ""
        , element3
        ]

```

Personally I don’t like this. the “do nothing”`text ""` is not expressive, and, when doing this for attributes, is not even trivial (`classList []` is the best solution I know). I’ve created tooling to make this, IMHO, nicer. It’s still a WIP but I’m using it in my current project right now. I’m curious if there’s already different common approaches to this that people think are nicer.

---

<div class="post-metadata">

**Author:** ![jackwilsdon](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jackwilsdon/32/2812_2.png) [@jackwilsdon](https://discourse.elm-lang.org/u/jackwilsdon)\
**Post date:** [February 29, 2020, 11:46pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/2 "2020-02-29T23:46:18Z")

</div>

There are some nice solutions in [this](https://www.reddit.com/r/elm/comments/b4uhqm/adding_an_attribute_based_on_some_condition/) reddit thread - it pertains to attributes but the same rules apply for element lists.

I think `text ""` is an alright solution provided it’s wrapped in something like this to make it more expressive:

```auto
module Main exposing (main)

import Html exposing (Html, div, text)

htmlIf : Html msg -> Bool -> Html msg
htmlIf el cond =
    if cond then
        el

    else
        text ""

main : Html msg
main =
    div []
        [div [] [text "Always here"]
        , htmlIf (div [] [text "Conditionally drawn"]) True
        , div [] [text "Always here"]
        ]

```

[View on Ellie](https://ellie-app.com/8bg4pYzB74ba1)

---

<div class="post-metadata">

**Author:** ![ursi](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ursi/32/3166_2.png) [@ursi](https://discourse.elm-lang.org/u/ursi)\
**Post date:** [February 29, 2020, 11:51pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/3 "2020-02-29T23:51:32Z")

</div>

This is more or less the approach I’m taking currently.

---

<div class="post-metadata">

**Author:** ![Brian\_Carroll](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/brian_carroll/32/444_2.png) [@Brian\_Carroll](https://discourse.elm-lang.org/u/Brian_Carroll)\
**Post date:** [March 1, 2020, 8:35pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/4 "2020-03-01T20:35:39Z")

</div>

Instead of replacing your element with a dummy element, you can leave it out of the child list.

```elm
view condition =
    div []
        ([element1]
            ++ (if condition then
                    [element2]

                else
                    []
               )
            ++ [element3]
        )

```

---

<div class="post-metadata">

**Author:** ![Hector](https://avatars.discourse-cdn.com/v4/letter/h/43a26b/32.png) [@Hector](https://discourse.elm-lang.org/u/Hector)\
**Post date:** [March 1, 2020, 11:12pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/5 "2020-03-01T23:12:23Z")

</div>

For elements, it seems it’s considered that `text ""` should be enough, although there is an open issue. [1]

For attributes there was this idea of a batch function [2]:  
`Html.Attributes.batch : List (Attribute msg) -> Attribute msg`

But the idea was dismissed by Evan himself later. [3]

[1] [https://github.com/elm/html/issues/53](https://github.com/elm/html/issues/53)  
[2] [https://groups.google.com/d/topic/elm-dev/6hmLG0iNm90/discussion](https://groups.google.com/d/topic/elm-dev/6hmLG0iNm90/discussion)  
[3] [https://github.com/elm/html/issues/103#issuecomment-313605792](https://github.com/elm/html/issues/103#issuecomment-313605792)

---

<div class="post-metadata">

**Author:** ![brian](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/brian/32/2180_2.png) [@brian](https://discourse.elm-lang.org/u/brian)\
**Post date:** [March 2, 2020, 3:49pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/6 "2020-03-02T15:49:57Z")

</div>

normally I define some simple helpers:

```elm
empty : Html msg
empty =
    Html.text ""

viewJust : (a -> Html msg) -> Maybe a -> Html msg
viewJust fn maybe =
    case maybe of
        Just a ->
            fn a

        Nothing ->
            empty

viewIf : (() -> Html msg) -> Bool -> Html msg
viewIf fn shouldDisplay =
    if shouldDisplay then
        fn ()

    else
        empty

```

These usually end up in a module like `Html.Styled.Extra` if I’m using elm-css (which is almost always) or `Html.Extra` if I’m not.

---

<div class="post-metadata">

**Author:** ![joelq](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/joelq/32/445_2.png) [@joelq](https://discourse.elm-lang.org/u/joelq)\
**Post date:** [March 2, 2020, 3:49pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/7 "2020-03-02T15:49:58Z")

</div>

I’m a big fan of pulling conditionals out of markup. It’s a bit more verbose but is much more readable.

```elm
expandable : Model -> Html Msg
expandable model =
  if model.isExpanded then
    expandedView model.items
  else
    collapsedView

expandedView : List Item -> Html Msg
expandedView items =
  div [class "expanded"] <| List.map itemView items

collapsedView : Html a
collapsedView =
  div [class "collapsed"] []

```

---

<div class="post-metadata">

**Author:** ![jouderianjr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jouderianjr/32/3009_2.png) [@jouderianjr](https://discourse.elm-lang.org/u/jouderianjr)\
**Post date:** [March 3, 2020, 1:05pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/8 "2020-03-03T13:05:29Z")

</div>

I use something close to what @brian posted, the only difference is the function name.

```elm
empty : Html msg
empty =
    Html.text ""

when : Bool -> Html msg -> Html msg
when shouldRender view =
    if shouldRender then
        view

    else
        empty

```

I’d prefer `when` because it seems nice when you do pipes:

```elm

div [class "d-flex flex-column flex-fill p-3"]
    [ errorView
        |> when (RemoteData.isFailure form.submissionStatus)
    , myCoolView
        |> when somethingElse
    ]

```

---

<div class="post-metadata">

**Author:** ![Jayshua](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jayshua/32/2707_2.png) [@Jayshua](https://discourse.elm-lang.org/u/Jayshua)\
**Post date:** [March 4, 2020, 10:17pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/9 "2020-03-04T22:17:02Z")

</div>

I use a couple of helper methods like the other examples, but which operate on List instead of Html.

```auto
concatMaybe : Maybe (List a) -> List a -> List a
concatMaybe maybe list =
    case maybe of
        Just toConcat ->
            list ++ toConcat

        Nothing ->
            list

add : a -> List a -> List a
add value list =
    value :: list

addMaybe : Maybe a -> List a -> List a
addMaybe maybe list =
    case maybe of
        Just toAdd ->
            toAdd :: list

        Nothing ->
            list

addIf : Bool -> a -> List a -> List a
addIf doAdd value list =
    if doAdd then
        value :: list

    else
        list

addIfMatches : (a -> Bool) -> a -> List a -> List a
addIfMatches predicate value list =
    if predicate value then
        value :: list

    else
        list

```

Then build lists of things with pipelines.

```auto
let
       attributes =
            [Css.tile]
                |> Build.concatMaybe maybeClickAttributes
                |> Build.concatMaybe (getLinkAttributes (config.linkTo data))
                |> Build.addIf shouldTransistion Css.transition

       children =
           []
                |> Build.add (Text.heading "Sponsor Information")
                |> Build.add (Text.paragraph sponsorDetails)
                |> Build.addMaybe (Maybe.map viewContactInfo sponsorContactInfo)
                |> Build.addMaybe (Maybe.map viewAdminInfo sponsorAdminInfo)
                |> Build.addIf showMoreLink (Element.link (Route.SponsorInfo sponsorId) "More Info")
                |> List.reverse
in
Html.div attributes children

```

This is nice because it looks basically the same as if you had written out a list - just imagine replacing `|>` with `,` and you nearly have a list literal.

Downside is you have to build things backwards because `::` prepends, or remember to use `List.reverse`. Doesn’t matter for attributes because their order doesn’t make a difference.

---

<div class="post-metadata">

**Author:** ![Hector](https://avatars.discourse-cdn.com/v4/letter/h/43a26b/32.png) [@Hector](https://discourse.elm-lang.org/u/Hector)\
**Post date:** [March 4, 2020, 10:44pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/10 "2020-03-04T22:44:36Z")

</div>

> [@Jayshua](#):
>
> Downside is you have to build things backwards because `::` prepends, or remember to use `List.reverse` . Doesn’t matter for attributes because their order doesn’t make a difference.

This was mentioned in the thread I linked before, and the order of attributes does matter.  
[https://groups.google.com/d/msg/elm-dev/6hmLG0iNm90/\_PIUjr0SCwAJ](https://groups.google.com/d/msg/elm-dev/6hmLG0iNm90/_PIUjr0SCwAJ)

---

<div class="post-metadata">

**Author:** ![Sebastian](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/sebastian/32/98_2.png) [@Sebastian](https://discourse.elm-lang.org/u/Sebastian)\
**Post date:** [March 5, 2020, 1:22am UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/11 "2020-03-05T01:22:32Z")

</div>

I have found `text ""` to be the most straight-forward an clear approach in most cases. So that is what we use.  
Dealing with element lists (for the purpose of returning `[]`) usually leads to code that is harder to work with and understand.

---

<div class="post-metadata">

**Author:** ![akoppela](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/akoppela/32/250_2.png) [@akoppela](https://discourse.elm-lang.org/u/akoppela)\
**Post date:** [March 7, 2020, 8:57am UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/12 "2020-03-07T08:57:58Z")

</div>

For empty view we define:

```auto
empty : Html msg
empty = Html.text ""

```

For empty attribute we define:

```auto
empty : Html.Attribute msg
empty = Html.Attributes.property "" Encode.null

```

Both are harmless and very usefull.

---

<div class="post-metadata">

**Author:** ![ursi](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ursi/32/3166_2.png) [@ursi](https://discourse.elm-lang.org/u/ursi)\
**Post date:** [March 7, 2020, 6:57pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/13 "2020-03-07T18:57:24Z")

</div>

`Html.Attributes.property "" Encode.null` does actually set a property on the DOM object though. `Html.Attributes.classList []` has absolutely no effect af far as I can tell, that’s why I prefer to use that.

---

<div class="post-metadata">

**Author:** ![dmy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dmy/32/702_2.png) [@dmy](https://discourse.elm-lang.org/u/dmy)\
**Post date:** [March 7, 2020, 7:24pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/14 "2020-03-07T19:24:39Z")

</div>

> [@ursi](#):
>
> `Html.Attributes.classList []` has absolutely no effect af far as I can tell

I think it does if no class is already defined, see:

> <https://github.com/elm/html/issues/141#issuecomment-534762063>
>
> When trying to render an attribute conditionally, one is forced to concatenate l…ists like this.
> \`\`\`elm
> div (\[style ("border", "red")\] ++ (if isAwesome then \[attribute "is-awesome" ""\] else \[\]) \[\]
> \`\`\`
> It would be nice to have something like an \`Html.Attributes.none\` attribute, which would make this simpler:
> \`\`\`elm
> div \[style ("border", "red"), if isAwesome then attribute "is-awesome" "" else none\] \[\]
> \`\`\`
> This would be especially useful for custom attributes.

---

<div class="post-metadata">

**Author:** ![ursi](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ursi/32/3166_2.png) [@ursi](https://discourse.elm-lang.org/u/ursi)\
**Post date:** [March 7, 2020, 7:58pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/15 "2020-03-07T19:58:24Z")

</div>

oh wow, you’re right. I thought I had tested that but I guess not 😕

---

<div class="post-metadata">

**Author:** ![jreusch](https://avatars.discourse-cdn.com/v4/letter/j/b5e925/32.png) [@jreusch](https://discourse.elm-lang.org/u/jreusch)\
**Post date:** [March 8, 2020, 3:53pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/16 "2020-03-08T15:53:56Z")

</div>

In that case, `text ""` would also have an effect on the DOM - it actually creates the empty text node!

```auto
div [] [text "", text "Hello, World!", text ""]

```

produces

 ![empty-text-nodes](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/9/91cd8e6b2abf14c43492fcd71b62a7e892981cf9.png)

---

<div class="post-metadata">

**Author:** ![akoppela](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/akoppela/32/250_2.png) [@akoppela](https://discourse.elm-lang.org/u/akoppela)\
**Post date:** [March 9, 2020, 2:02am UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/17 "2020-03-09T02:02:23Z")

</div>

Yes it does. And that property is `""`. So unless one wants to define a unnamed property of a node it should be fine. In practice that’s a very edge case. Thanks for pointing that out, it maybe useful for folks to learn.

---

<div class="post-metadata">

**Author:** ![ursi](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ursi/32/3166_2.png) [@ursi](https://discourse.elm-lang.org/u/ursi)\
**Post date:** [March 10, 2020, 10:40pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/18 "2020-03-10T22:40:20Z")

</div>

My world is falling apart!

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [March 20, 2020, 10:40pm UTC](https://discourse.elm-lang.org/t/are-there-any-common-patters-for-dealing-with-conditionally-including-markup/5242/19 "2020-03-20T22:40:24Z")

</div>

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