These days, most front-end developers agree that UIs should be built in a component-oriented fashion. If you’re curious about that larger conversation, there are plenty of good resources on that out there: We’d highly recommend the excellent Style Guide Podcast — yes, all twelve episodes are well worth listening to — as well as Atomic Design to get a sense of why this matters.
Implementing a component-based approach can be a challenge. Generally speaking, it’s a good idea to maintain an application-independent style guide / component library, not least because it tends to result in more well-crafted components (e.g. regarding documentation, reusability and robustness). These days, we can choose from numerous tools to set up a library like that (e.g. Pattern Lab or Fractal).
Even so, you probably still want some sort of abstraction to generate components' server-side markup[1] within your application, both for convenience and encapsulation:
(<image-gallery>
here is a
custom element,
which unobtrusively takes care of client-side augmentation.)
Whenever we need to generate such complex HTML structures within our templates, we just want to invoke something like a function with the respective parameters:
Well, that’s pretty much exactly what we’ve done in our latest project — which happens to use Haml („HTML Abstraction Markup Language“), though this approach should work just the same with ERB or whatever templating language you prefer[2]:
Note that any parameters are passed in explicitly, which ensures that each component has a well-defined contract.
Components may also support blocks to allow for composition:
Behind the scenes, component
is just a tiny wrapper around the built-in
render
Rails helper:
Whenever component
is invoked, it renders the respective markup partial from
the corresponding directory in app/components
[3] (e.g.
app/components/image_gallery/_image_gallery.html.haml
). That directory
typically also contains whatever else the component might require, such as CSS
and JavaScript assets as well as i18n translation files:
We’d be happy to elaborate on that aspect some other time — let us know in the comments.
-
Distinguishing between server–side base markup and augmented client–side DOM structures improves performance, robustness and generally makes us a good citizen of the web — but that's a topic for another day. ↩
-
At least one of the authors is not particularly, err, partial to Haml. ↩
-
For this to work, we've extended
ApplicationController
to includeappend_view_path Rails.root.join("app", "components")
. ↩