Crafting a nice UI can suck up a lot of time due to its stateful nature. We’re all familiar with this cycle: make some tweaks, reload the app, navigate to the relevant page, click around and type for a while to get the right state, only to see that the spacing in one of the dropdowns still doesn’t look quite right. Rinse and repeat.
If you use something like elm-live
, you can cut out the reload step and have it done automatically on every code change. But you still need to do the rest of the steps to get to the particular widget and put it into a specific state.
But what if you could instead lay out your UI elements on a single page, so that you can see them instantly and compare them side-by-side? What if you could show them in any particular states that you want, without clicking around pages and manipulating widgets to get them into the right condition? UICards help you do just that!
With it, you can design a consistent, good-looking UI with less effort. You can also avoid the time consuming retrofits that are likely if your UI largely evolves page by page without an overarching plan.
Say you have a registration form with some validation. It can be in different states, and UICards allows you to seem them side by side:
You can tweak the font weight and see how all these states look after the change:
Combine this with live reloading (eg using elm-live
), and you can now have instant feedback as you make changes to the UI widgets.
Of course, static widgets are just one part of the story. What about all those interactive aspects of the UI? Say you have interactive widgets, like a menu that slides out from the side. Do you have to go back to the app to test it and get the animation just right? Not really! Thanks to the fact that all the state is in the model, and all the messages are handled by one update
function, UICards allows you to have fully interactive cards. For example, we can test the functionality and user experience of a color picker which requires state and message handling:
You need to install UICards with elm install alexkorban/uicards
.
This is what the code for the registration form cards shown above could look like, assuming the application code defines Main.registrationForm
:
module Cards exposing (main)
import Main
import UiCards exposing (..)
initialModel =
let
flags = ()
in
Tuple.first <| Main.init flags
main =
show Main.update
[ deck "Forms"
[ card "Blank registration" initialModel <|
\_ ->
Main.registrationForm initialModel
, card "Invalid registration" initialModel <|
\_ ->
let
failureModel =
Main.register
initialModel { userName = "InigoMontoya", password = "" }
in
Main.registrationForm failureModel
]
]
The cards are organised into decks. You view one deck at a time, and can switch between them in the UI.
The entry point for UICards is the show
function. It takes an update
function (in this case, we’re using the application’s update function) and a list of decks.
The card
function takes a name, the initial model value, and a Model -> Html msg
function as its last argument. The reason that it takes a function and not just a Html msg
value is the support for interactive cards which get updated as the model changes.
Since the cards above are showing static UI elements, I’ve ignored the model
argument and used initialModel
and failureModel
to render different versions of the registration form.
You can find more details in the documentation.
Several years ago, I stumbled upon Bruce Hauman’s post about his devcards project for ClojureScript. It stuck with me because it was such a great idea, and I wanted to see whether I could implement something similar in Elm. Typically this type of tool is simpler to implement in a dynamically typed language like ClojureScript.
At this point, UICards are experimental, and I just got to the point where I thought that it might be useful to other people. I have a lot of ideas for improving UICards:
index.html
.If only I had a corresponding amount of time to turn these ideas into code!
Finally, I’m also going to write a post explaining how UICards are implemented. If you’d like to get notified when it’s out, pop your email into the form in the footer ↓.