Elm-Ui-Widgets - A collection of Widgets for Elm-Ui

After about a month of tinkering, I proudly present: Orasund/elm-ui-widgets

Essentially a collection of reusable views (and some components) written in Elm-Ui.

Examples of all widgets can be found here. For styling, I used my own Orasund/elm-ui-framework.

Why create such a package?

After looking at the current packages that implement various reusable views (and components) I noticed two things:

  • There are (nearly) no widgets for Elm-Ui, and that’s a problem because while going from Element to Html is easy, the opposite is not always possible (as a lot of styling in Elm-Ui would not be adapted to the Html element.)
  • There is no collection of widgets, all in one place. A lot of components get reimplemented over and over again. It’s hard to keep track of what package is currently the best.

This package tries to solve both of these problems.

Why does this package also include components?

I wrote a component whenever the wiring of a similar reusable view results in more effort than the boilerplate of the component.

Where will it go from here?

I really would like to write a native material-design implementation in Elm. But after doing this package as a first step, (Which I already wrote while having the material.io docs as reference) I am not quite sure how I can avoid a lot of boilerplating. It seems like a Master View Type would be the solution, but I’m not quite sure how I can ensure the customizability when my entire page can be described as a single type. (I don’t want to know how many parameters such a type would need).

16 Likes

I might try this when I continue working on the user interface for my project.

Hi Lucas,

thank you for sharing this! I am happy to see a library that offers a collection of widgets and one that targets elm-ui in one package.

I am especially curious about avoiding boilerplate in a package like this, and I am wondering if I can share an experience of mine with you regarding that. I am not immediately seeing a relation to the master view type pattern, so I might be misunderstanding you. I will share it anyways:

In elm-mdc, also a native(-ish) material design implementation in Elm, albeit with different goals from what you describe, we introduced a “widget store” that is basically the sum of Dict String widgets for any widget type. The individual widgets would then index into that store by String identifiers. I have found that to be a good technique to minimize the boilerplate per widget that one might otherwise need.

In case that is something that interests you, and my explanation is a bit sparse (most likely), please let me know and I can elaborate!

The idea behind a Master View type (I hate that name, but can’t think of a better one),
would be to have a type that represents your entire page. You wouldn’t have any boilerplate any more, because the package would do everything for you. But the problem here is that it hard to customize.

Here is how my current implementation of such a Type would look like:

type Widget msg
    = TextButtonWidget (TextButton msg)
    | IconButtonWidget (IconButton msg)
    | ToggleButtonWidget (ToggleButton msg)
    | FAButtonWidget (FAButton msg)
    | SpeedDialWidget (FAButton msg)
    | CardWidget (Card msg)

type TextButton msg
    = TextButton
        { emphasis : ButtonEmphasis
        , label : String
        , enabled : Bool
        , onClick : msg
        , icon : Maybe (Svg Never)
        }

type ButtonEmphasis
    = Low
    | Default
    | High

type IconButton msg
    = IconButton
        { enabled : Bool
        , onClick : msg
        , icon : Svg Never
        }


type ToggleButton msg
    = ToggleButton
        { options :
            List
                ( String
                , { enabled : Bool
                  , onClick : String -> msg
                  , icon : Svg Never
                  }
                )
        , selected : Maybe String
        }

{- ... -}

and then I would write a function like

{ init : model
, widgets : model -> Widget msg
, update : msg -> model -> model
}
-> Program () model msg

that takes care of the boilerplate for me.

I could even use extendable records to ensure that widgets with less required wiring could be applied to a Widget msg -> Html msg function. (Check out Richard Feldman’s talk about Elm-css, if your curious why I’m talking about extendable records)

The problem here is that if I want to make anything customizable, I need to put those options either in a Config type or in the Widget type. So I’m still not sure if this is actually a usefull idea.


I also thought about your approach: Having a widget store that sort of mimics the mutable behaviour of components. Then the user would set up the store once and “register” new widgets to it. The problem here is that I feel like it might be a bad idea to trust the programmer that they ensure each id is actually unique.


So in conclusion, yeah maybe I need help, maybe not. I don’t know. I’ve not yet decided if I actually want to work on this. But I’m guessing that if I want to go the full mile and return a complete progamm, then internally I will properly use a widget store like you described.

1 Like

Hi Lucas,

thank you very much for elaborating! I do understand what you’ve meant better now.

I would be very curious how that would turn out! So if you do attempt that approach, be sure to post its outcome again here!

Regarding the “widget store”, I want to make two clarifications that were not identifiable from my original description. You are right in saying that a “widget store” requires wiring (say, init, subscriptions, update) and that then widgets are free with respect to boilerplate. I have not found naming widgets an issue for two reasons:

  • establishing a hierarchical naming schema eliminates a big class of potential collisions, ie. “save button on page a” and “save button on page b”
  • you may have as many "widget store"s as you like and identifiers have only to be unique within that store, ie. one widget store per page

Keep us posted as you progress! :slight_smile:

This is a great idea! I use elm-ui,and am rubbish at ui design, so I have been looking for something simple to do the hard work …