He goes into detail about designing an API for customising buttons with some core goals in mind - the api should be
Consistent
Flexible enough to allow variations
Constraining (not too much variation)
Have sensible defaults
Prevent misuse
The API we end up with uses an opaque data structure to configure a button:
type Button msg
= Button (Options msg)
type alias Options msg =
{ size : Size
, fill : Fill
, onClick : msg
, text : String
}
type Fill
= Outline
| Solid
type Size
= Small
| Medium
| Large
It exposes a button with default options:
button : msg -> String -> Button msg
button onClick text =
Button <| defaultOptions onClick text
defaultOptions : msg -> String -> Options msg
defaultOptions onClick text =
{ size = Medium
, fill = Outline
, onClick = onClick
, text = text
}
And exposes a set of functions to customise the options on the button, e.g:
solid : Button msg -> Button msg
solid (Button options) =
Button { options | fill = Solid }
large : Button msg -> Button msg
large (Button options) =
Button { options | size = Large }
The key here is these functions compose nicely (so they can be piped). We end up with a lovely API that looks like this:
I started using this pattern at work to implement a design guide we got from a designer: it's honestly one of the nicest APIs I've used - it's so simple, flexible and powerful and the key thing for me is that it's painless to extend when you find you need more options (it's insane how many subtle variations buttons need). I'm in love 😍.
Going to experiment with this pattern for building other UI elements (one that springs to mind is something like cards).
Highlighting Brian Hicks's talk at Elm in the Spring Conference:
https://www.youtube.com/watch?v=PDyWP-0H4Zo
He goes into detail about designing an API for customising buttons with some core goals in mind - the api should be
The API we end up with uses an opaque data structure to configure a button:
It exposes a button with default options:
And exposes a set of functions to customise the options on the button, e.g:
The key here is these functions compose nicely (so they can be piped). We end up with a lovely API that looks like this:
When we're done with the configuring, the API exposes a function like
toHtml
which takes those options and makes a html button to use in a view:So
myButton
becomes:I started using this pattern at work to implement a design guide we got from a designer: it's honestly one of the nicest APIs I've used - it's so simple, flexible and powerful and the key thing for me is that it's painless to extend when you find you need more options (it's insane how many subtle variations buttons need). I'm in love 😍.
Going to experiment with this pattern for building other UI elements (one that springs to mind is something like cards).
Kudos to Brian for his fantastic talk ✨