photo by Guillaume Bolduc

I'm a big fan of component-based tools. This is what draws me to React and Vue as tools for everything I do on my own, and what makes me excited about tools like Invision Studio and Framer X on the design side. It's the definition of the Don't Repeat Yourself principle for me — you design and implement a component once and then you can reuse it multiple times. If new data suggests that all 134,842 instances of the component across 143 apps and websites needs to be redesigned, the team doesn't have to redesign all 134,842 x 143 instances and making sure everything works — they can just redesign in one place, update the UI framework everywhere and the rest is just making sure nothing broke after the updates. It saves incredible amount of time, especially if you're working with an organization that launches a lot of small things, all the time — marketing landing pages are a great example.

Recently, I've been thinking how to achieve the same effect without React. In the current setting, I'm basically stuck with Rails web apps using all sorts of layout engines, but mostly either Haml or Slim. The team is mostly consisting of people who don't really do front-end that much (they will if they have to, but they're mostly focused on infrastructure side of things), so ideal separation of responsibilities would be having components where developers only have to care about I wanted a solution. I think I came up with a plan.

Separation Level 1: Styles

First of all, we're outsourcing everything that can be outsourced to a third-party library. We've decided that we don't want to care about grid frameworks and the current implementation of it, perfect implementation of box-shadows and so on. In this case, we're outsourcing all of that to Bootstrap, but that's literally only because the developers who are mostly working on front-end tools just know Bootstrap the best. You can use whatever you want and what works for your team.

All the default components that are coming from the framework are getting styled to match the design system, which means that if someone wants to write raw, Bootstrap-flavored HTML, everything should look right, provided they don't go crazy with it. That way, we end up with something that's already way more maintainable and harder to break.

For that, we've created a custom NPM module that includes all the styles for default and custom components that developers can simply add through Yarn from a private repository and it generally works.

Separation Level 2: Standard Components

This is where it gets interesting. I wanted to get to the point, where the developers could just create a component without worrying what the proper structure of HTML is. What I wanted to replicate is React-like way of embedding components inside components that lets people simply write structures like this:

<HeroSection type="small" headline="Welcome to our website">
    <Button label="Get in touch" url="/contact">

This is easily possible with React and I wondered how to do it in our case, where Rails or React are responsible for layout. For a while I thought if WebComponents is the solution I'm looking for, but the support is still quirky.

What I learned though, is that in Rails, you can simply write parametrized partials and use yield, content_for and locals to make components reusable. That way, I can currently define all our common components using this way:

<div class="hero">
    <%= yield %>
    <% if defined? headline %>
        <h1><%= headline %></h1>
    <% endif %>
    <% if defined? subheadline %>
        <h2><%= subheadline %></h2>
    <% endif %>
    <% if defined? button %>
        <a href="<%= button[:url] || '#' %>" class="btn btn-lg btn-primary <%= button[:css_class] || '' %>">
            <%= button[:label] %>
    <% endif %>

In that case, the usage of the component in Rails-based app would be:

<%= render partial: "components/hero", 
    locals: {
      headline: "Welcome to our website!"
      subheadline: "Our website is pretty great!"
      button: {
        css_class: 'btn-special-type'
        label: 'Learn more'
        url: '/page'
    } do %>
    <%= render partial: "components/navigation" %>
<% end %>

We can keep those components as partials in a Ruby gem that gets included across the websites, making it pretty bulletproof. While it brings a bit of a learning curve with it, I found it way less error prone than having developers remember all the CSS classes and HTML structures of every component, especially when it's documented well.

The future

Right now, it works pretty great for all the Rails-based websites and web apps and does the separation of responsibilities well enough — I can edit HTML in the component and it gets distributed nicely across all websites. I was also looking for a way to make it work with Handlebars using the parametrized partials they provide, but I'm not sure if it can be done without introducing an extra level of abstraction that ends up compiling into something that both Rails and Handlebars would understand. As I get higher and higher in levels of layout abstractions, I'm basically landing on React components, which would literally be the best solution, but given the resources and the learning curve, that's not a feasible solution.

Do you have an idea how to make that happen? Shoot me an email.