n1kben/elm-css-hooks/1.0.0

NOTE: the latest version is 1.0.2

CssHooks

Make Elm inline styles respond to selectors and CSS at-rules. Start with a base style, then use on to change it when a condition matches.

config =
    CssHooks.define (\hover -> { hover = hover })
        |> CssHooks.add "&:hover"


buttonStyle =
    [ ( "background", "navy" ) ]
        |> CssHooks.on config .hover
            [ ( "background", "blue" ) ]


view =
    Html.div []
        [ CssHooks.styleElement config
        , Html.button [ CssHooks.attribute buttonStyle ] [ Html.text "Save" ]
        ]

define gives the condition a name. add supplies its selector and registers the CSS rule. Put styleElement config in the page once; the style values on each element remain inline. The CSS Hooks introduction explains the CSS custom properties behind this.

Configuring hooks

type Config a

The conditions created by define and add, along with their stylesheet rules. The type parameter is the record of names you choose for the conditions.

A condition created by add, or a combination made with and, or, or not. Use one with on to change an inline style.

define : a -> Config a

Start a config. The function names the conditions supplied by later add calls. Its arguments and the add calls must be in the same order:

CssHooks.define (\hover wide -> { hover = hover, wide = wide })
    |> CssHooks.add "&:hover"
    |> CssHooks.add "@media (min-width: 600px)"
add : String -> Config (Condition -> a) -> Config a

Add a selector or at-rule. This registers its stylesheet rule and supplies its condition to the function in define. Each call fills one argument of that function. Supported at-rules are @media, @container, @supports, @scope, and @starting-style.

config =
    CssHooks.define (\hover -> { hover = hover })
        |> CssHooks.add "&:hover"

Use & to mark the styled element in a selector. For example, &:hover matches the element when hovered; .group:hover & matches it when an ancestor with the group class is hovered. Elm does not check selector syntax, so pass trusted strings to add.

Styling elements

type alias Style =
List ( String, String )

CSS property and value pairs. Write property names in kebab case and include units where needed, as in ( "padding", "12px" ). Elm does not check CSS syntax in these strings.

on : Config a -> (a -> Condition) -> Style -> Style -> Style

Set properties when a condition matches. Select a named condition with a record accessor such as .hover, or combine conditions with a function such as (\c -> CssHooks.or [ c.hover, c.wide ]).

Start with a base style and pipe it through on. Each call takes the config, the condition to select, and the properties to change:

[ ( "background", "navy" ) ]
    |> CssHooks.on config .hover [ ( "background", "blue" ) ]

You can use multiple on calls. The later call wins if two calls set the same property. A property with no base value falls back to revert-layer when its condition does not match.

Avoid mixing a shorthand such as margin with a longhand such as margin-left on the same element.

attribute : Style -> Attribute msg

Turn a style into one HTML style attribute. Apply on before calling this function.

Html.button
    [ CssHooks.attribute [ ( "color", "white" ) ] ]
    [ Html.text "Save" ]
styleElement : Config a -> Html msg

Add the hook stylesheet to the page. Place this element once near the root of a view that uses on with this config.

styleSheet : Config a -> String

Get the stylesheet as a string, for use when you manage the page's CSS yourself. Include it once. For Elm views, styleElement does this for you.

Combining conditions

Match when every condition matches. An empty list always matches.

CssHooks.on config
    (\c -> CssHooks.and [ c.hover, c.wide ])
    [ ( "background", "blue" ) ]

Match when at least one condition matches. An empty list never matches.

CssHooks.on config
    (\c -> CssHooks.or [ c.hover, c.wide ])
    [ ( "background", "blue" ) ]

Match when a condition does not match. For example, not c.wide matches widths below the registered media query:

CssHooks.on config
    (\c -> CssHooks.not c.wide)
    [ ( "padding", "8px" ) ]