Skip to content

Instantly share code, notes, and snippets.

@dwayne
Last active August 7, 2023 08:34
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dwayne/1455037aefe52c1786188fd35f70eaee to your computer and use it in GitHub Desktop.
Save dwayne/1455037aefe52c1786188fd35f70eaee to your computer and use it in GitHub Desktop.
Elm Odds and Ends

Custom Properties in Elm

Html.Attributes.style does not support setting custom properties. For e.g. the following won't work:

style "--alert-text-color" "#123456"

re: Asking for support

A workaround

attribute "style" "--alert-text-color: #123456"

re: Passing variables to CSS, Setting the gutter

Potential pitfalls

However, it doesn't work well when other styles need to be set. For e.g. the following doesn't work:

H.div
  [ style "background-color" "black"
  , attribute "style" "--alert-text-color: #123456"
  ]

re: It doesn't stack

The use of attribute "style" overwrites the previous styles value set by style. Order is important when using this solution to ensure you don't overwrite previously set styles. So the following works:

H.div
  [ attribute "style" "--alert-text-color: #123456"
  , style "background-color" "black"
  ]

I personally don't see it as a problem since the only time I'd want to be using the HTML style attribute in my Elm code is when I want to use custom properties. For other uses of the HTML style attribute I think CSS classes in an external stylesheet are better suited.

If you really need to set both then the following snippet provides a workaround:

styles : List (String, String) -> H.Attribute msg
styles =
  HA.attribute "style"
    << String.join "; "
    << List.map (\(name, value) -> name ++ ": " ++ value)

Now you'd be able to set custom properties along with other properties in any order you'd like:

styles
  [ ( "border-color", "green" )
  , ( "--circle-x", String.fromInt position.x ++ "px" )
  , ( "--circle-y", String.fromInt position.y ++ "px" )
  , ( "border-width", "3px" )
  , ( "--circle-diameter", String.fromInt diameter ++ "px" )
  , ( "background-color", "pink" )
  ]

A special case: You only need to set custom properties

If you only need to set a bunch of custom properties then we can make it so that you don't have to type all those "--" at the beginning.

customProperties : List (String, String) -> H.Attribute msg
customProperties =
  HA.attribute "style"
    << String.join "; "
    << List.map (\(name, value) -> "--" ++ name ++ ": " ++ value)

For e.g.

customProperties
  [ ( "circle-x", String.fromInt position.x ++ "px" )
  , ( "circle-y", String.fromInt position.y ++ "px" )
  , ( "circle-diameter", String.fromInt diameter ++ "px" )
  ]

What about setting custom properties on :root?

There is a hacky solution I figured out after I stumbled upon the use of an HTML <style> element in elm-css.

H.div []
  [ H.node "style" []
      [ H.text ":root { --theme-background-color: #3241AF; }" ]
  ]

For e.g. I used this approach in my elm-2048 clone to control the tile movement duration from Elm.

The problem with this solution is that it uses an HTML <style> element in the <body> element. According to the HTML Standard the <style> element should only be used

In a noscript element that is a child of a head element.

However, browsers may not really care according to Jukka. 😕

Summary

Elm doesn't provide support for CSS custom properties out the box. However, there are a few acceptable workarounds that I've mentioned that you can use for now. I'd be interested to learn about other scenarios where these workarounds won't work.

Examples of scenarios I haven't tried:

  • CSS frameworks that can be configured with CSS custom properties
  • Web components that can be configured with CSS custom properties

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment