Ironically, in our front-end code the views often get the least love. In non-trivial apps they quickly become a nested tangle of tags, classes, and conditional logic. Extracting functions can only go so far. There is a better way.
Join me on a quest to turn our views from HTML soup into a domain-specific description of our UI elements. We'll explore several strategies for achieving this including both the top-down, bottom-up, and layered approaches to structuring functions. You'll leave empowered to write view code that's both flexible and readable.
The view is an often neglected part of our code. It tends to be made up of large chunks of nested HTML functions, riddled with duplication, and punctuated by conditionals. Many try to combine state and UI by trying to create "components". I've found a simpler approach yields great results.
We can use regular functions to add a thin level of abstraction above the HTML
helpers. We end up writing something that almost looks like a "domain specific
language" describing the various visual elements we use on our page. For
example a survey view might be described in terms of "section", "multiple choice
question", and "free-form question". Whether these are implemented as nested
div
s or as table
s is irrelevant most of the time we're working in that code.
This leads to tremendous readability boosts by focusing on the higher-level concepts that actually matter in the view. In addition, building views like this decouples them from the HTML structure and CSS classes used to implement them, allowing them to be easily modified and shared.
I'll be looking at several examples including more specialized views like surveys and shared app UI pieces like tables and titled sections.
Some concepts I'll be exploring are:
- Building from the top-down (passing all the data into the top-level function)
- Building from the bottom-up (passing constructed children to the parent function, similar to the Html library)
- Handling messages and events
- Decoupling content from decisions
- How to deal with special cases
- Avoiding the traps of over-abstracting and over-configuring
- The "layered" architecture of building-lower level functions that take many arguments and then defining higher-level functions with fewer args for the 80% case in terms of the lower-level ones.
I've consulted on multiple Elm projects as well as been active helping people online. In most non-trivial apps, the view code tends to be a low-level tangled mess once the app reaches a certain size. I've had great success avoiding raw HTML functions in my views in favor of higher-level semantic helpers. The reaction from clients and colleagues has been overwhelmingly positive.