Pattern libraries are a valuable tool for any project where the UI needs to scale or be iterated on. Although they aren’t without shortcomings, they – amongst other things – facilitate; improving the modularity of our frontend code, expediting design decisions, maintaining design consistency, improving refactoring and serve as a reference for uninitiated team members joining a project.
Whilst generally being of the opinion that they’re “a good thing”, we’ve generally struggled to provide an easy way of introducing them consistently for each project. One challenge we faced is that our project work is generally quite varied, and subsequently the technology stack that supports the project can be varied too, so we couldn’t rely on a coupling between a particular stack and a pattern library generator.
After some internal discussion we decided we wanted a solution that would accommodate our preferred CSS organisational structure (inspired by ITCS), be customisable per project, allow us to work on HTML and CSS without a dependency on the actual project and be easy to transfer code across projects.
Fabricator is a pattern library generator built on Node.js. Its beauty is that it allows us to have an independent dedicated tool for building and documenting the projects’ UI.
Using Assemble for its templating engine and its build system in gulp, it gives us an amazingly customisable and familiar platform, and a low barrier to entry in getting it running across the team.
Fabricator allows us to define our “Materials” or the language we use to describe our design system. We customised our fork of Fabricator to include objects, components and views. A simple separation encouraging the breakdown of UI into smaller components and then subsequently compositing larger UI out of them.
Fabricator has a nice way of encouraging a modular approach to your UI development. Each material can be included into another, and variations of material can be grouped. In practice that allows things such as the following grouping of a
button objects variants, and then the use of the large variant in the
Fabricator’s approach to grouping modifiers (duplication under a directory) doesn’t feel terribly scalable. However, there are ways around it and there’s an argument that if you have a significant amount of modifiers, your component or object is probably doing too much, so the jury is still out on my opinion there.
One major benefit that became apparent while using Fabricator was the way it was decoupled from the main project stack. Designers and other frontend developers can just boot-up the pattern library and make contributions without having the main application running. Cloning the project repository and a simple
npm start in the pattern library directory is the only command you need to run. It also doubled up as a bit of sandbox for prototyping designs which was a nice side effect.
Forking and priming new projects
As part of refining our workflow we wanted to take all of our ‘common patterns’ and make them available for every new project. To paraphrase Ben Callahan from Sparkbox:
“[we] want to go deeper in solving problems with customers, look at the problems we’ve solved, and boil them down into a core.”
This resonated with me quite strongly. At UVD we’re concerned more about delivering the customer value, rather than pontificating over mark-up for design patterns that we, or the community, have already solved. We forked Fabricator and customised it to our needs, occasionally merging in changes upstream from the main Fabricator repo to try and keep it in sync with the main project.
This forked repo now serves as the starter point for new projects, and consequently also hosts all of our CSS best practices and tooling.
Through using Fabricator what we end up with is a stand alone pattern library for every project. This helps us in our iterations as we can review a projects’ pattern library on the next sprint to familiarise ourselves with the design direction. It also assists with regression testing as all patterns are available in one area, a CSS change that exceeds its intended jurisdiction will be easier to spot within the pattern library than in the project itself.
With Vote for Policies we hosted this externally to try and help the open source effort on their data site. There were definitely things we could have done better here but it was a big step in the right direction.
Overall, Fabricator has been a really nice fit into the evolution of our workflow. We initially tried rolling our own, but with some great community efforts and being a reasonably small team, we feel our energy was better spent supporting those projects. That’s not to say that Fabricator is the only option out there, or it’s a good fit for everyone, but I’d definitely recommend checking it out. I’d also be interested in hearing how other digital agencies are solving this particular problem, so do let me know.