Here at Clearleft we've been building website component libraries (often also called pattern libraries or styleguides) for quite a while - in fact very few projects that we've worked on over the last five or six years have not had the front-end portion delivered as some form of componentised, modular design system.
By and large, the component library has proven to be an effective, robust format for delivering documented code and design patterns to our clients. And at the same time, the process of thinking and building in this componentised manner has been instrumental in shaping our own iterative design/development workflow.
Whilst the philosophy has remained the same, how we put our component libraries together has evolved greatly over the years. Some of this has been driven by our better understanding of the problems we are trying to solve with them; some has been driven by technical change; and a lot has been driven by the need to make our code deliverables work in the context of increasingly large and complex projects and for projects that are delivered in an agile, iterative design/build/implement loop rather than a 'old fashioned' waterfall approach.
So I thought I'd make a few notes on some lessons that I've personally learned in seeing our own take on this format evolve over the last few years, a few potential pitfalls to avoid and some tips on how to build and deliver pattern libraries to best suit the needs of your clients.
Before I start though, let's be clear - this is about tooling and the format of website component libraries, not their contents. There are many great articles around on how best to modularise your site code, develop design systems, and name everything meaningfully. My focus however is on the things we've learned in the process of trying to find the best way to wrap all this up into a package that fits well with the specific needs of individual projects.
Language is important
Libraries, styleguides, components, patterns, modules, layouts, pages, atoms, molecules, organisms, blocks, modifiers, variants... there is a lot of domain-specific language floating around this niche corner of design and development. Like with anything, language can either clarify or obfuscate, and so it's important to define and then be consistent with the words that you are using on your projects.
Brad Frost's Atomic Design methodology is appealing to many people in part because it provides unambiguous terms with clear definitions to help describe the moving parts within a componentised design/build system. It's a bit too prescriptive for my taste however, and whilst I appreciate the analogy I find the terms (atoms, molecules, etc) a little too abstract. But that's just personal preference. The important thing is to find something that works for the project you are working on, document it and then apply it consistently throughout that project.
For my part, I find terms like 'styleguide' and even 'patterns' to be quite problematic in the generic sense that they are often used. The word 'styleguide' has so much baggage attached to it relating to its use over the years as a static design deliverable that I generally try and avoid it altogether. 'Patterns' I do use, but less as a generic term and more for a specific type of 'component'.
So for example, I find that an agreed on, suitably generic term for the 'bits' within a modular design system is essential. As you may have noticed, I personally favour use the word 'component' for this:
"Component: A generic term to describe a piece of the website UI. It can refer to a single static HTML element, a whole page or (more commonly) something in between. At its bare minimum it will consist of just a piece of markup, however more complex components can also potentially include styles, behaviour, tests, documentation and more."
Following on from that, I can then define the term 'component library' as:
"Component Library: A collection of components, organised in a meaningful manner, and often (but not necessarily) providing some way to browse and preview those components and their associated assets."
I like this definition of a component library because it doesn't place any assumptions on the shape or format of the deliverable - in theory it could just be a Git repository of plain HTML files, or it could be something built specifically for (and wrapped up in) preview tools like Pattern Lab or Fabricator.
But regardless of what terms and definitions you use, consistently applying them and making sure that they can be reflected in the structure of your deliverables is key to avoiding headaches and miscommunication later on down the line.
Be clear on what you are building
The appropriate format and structure for your component library is very much tied into two key things:
- Who you are.
- The end goal of the component library.
Being clear on these two things before starting a project is key to figuring out the best possible system/tool to use will be. Often off-the-shelf tools for building component libraries have been designed with a particular combination of these two points in mind, and using any tool whose use-cases don't align with your own may result in a solution that causes more problems than it solves.
Who you are
If you have got this far into this article, you are likely part of:
- An agency building component libraries for clients
- An in-house development team
Or a freelancer working in one or both of those environments. This is an important question, because it can fundamentally shape the way that the library needs to be structured and what it needs to contain.
The goal of the component library
How will the component library you are building be used? It might be:
- A deeply integrated, living part of a website or application's codebase.
- A code and documentation deliverable for implementation by an in-house team.
- A code and documentation deliverable for implementation by a third party development agency.
- A reference document for different teams in the same organisation, to ensure consistency between sites and/or platforms.
- A public facing site, predominantly for external marketing purposes.
- Any combination of the above (or the many other potential uses!).
Even more perhaps than the first question, how the component library will be used will likely be a major determining factor in the format of the final output.
Why it matters
At Clearleft we are an agency that delivers front-end code (amongst many other things) to clients. We usually hand over the code we write to either the client's in-house developers or a third-party back-end development agency for implementation into whatever application or CMS is being built. The libraries we hand over actually rarely live on in the format that we deliver them - instead they are often serve as more of a kind of 'implementation documentation' for other developers. We always encourage our clients to use what we deliver as a starting point for a more integrated, 'living' component system, but integration is hard and how to persist the work we deliver is a per-project consideration, and often largely determined by the depth of the client's commitment to deeply integrating a modularised, component-based design and development mindset into their everyday workflow.
This focus of a component library as implementation documentation is, I suspect, a relatively niche use case. But it means that what we need to provide and how we need to present it is quite different from - for example - an in-house team who are building a bespoke component library / styleguide website largely for external marketing purposes.
All combinations of these two things present their own individual challenges, and the key thing is to appreciate what it means for what you need to deliver and the format it should take. An off-the-shelf tool may well be the right solution for you - but be honest in your appraisal and don't be afraid to build something bespoke if you think that it will be a better fit for your own set of circumstances.
The library is not the tool, the tool is not the library
It's important to be extremely clear on the distinction between the content of the library of code you are building and whatever tool you are using to author/preview/present your components. It may sound obvious, but it's often actually quite hard to keep the two things from bleeding into one another, to the detriment of both the quality and the longevity of the code that you are creating.
File-structure first development
In my opinion (and providing you are not using some sort of database-backed component library solution), the actual physical file structure of the components you build should be able to stand alone as a deliverable. I should be able to browse your repository in a meaningful manner, identify the components, the hierarchy within which they live (if any) and be able to find the assets for the site without too much bother. What I should not have to do is read a lengthy README.md to understand where to look for components, to know to avoid the
_app folder, or how to interrogate some JSON configuration to discern which components are pages and which are patterns.
Don't get me wrong, I love READMEs and JSON configuration files - the tool we use for authoring component libraries at Clearleft makes heavy use of such things. But I like to believe that the tool is effectively an optional dependency of the deliverable; the underlying structure of files and folders presents a meaningful interface to help you understand the component library even without any UI generated around it.
Build for implementation, not for your tool
Another way that I see tooling and deliverables get mixed into one another is when there is a mismatch between opinionated component library tooling and the tools that the final implementation will use. This is often one of the issues that makes integrating component libraries (often built by the front-end 'design' team) with the production site or application (often being built by the 'proper' development team) even more challenging than it needs to be.
Let's take an example: The team building the 'proper' application are using Node with Nunjucks Templates, and Webpack for asset bundling. They have been given a component library, designed and developed by an external agency while they were setting up the back-end business logic, to implement into the application. However the component library has been built with a tool that enforces the use of Handlebars templates and Gulp for asset compilation. This mismatch mean that the dev team are effectively left to grabbing the generated static HTML, re-templating it in Nunjucks and figuring out a way to re-implement the Gulp tasks in something that they feel more comfortable with. It's not impossible... but it's certainly a waste of effort.
Now obviously this scenario could have been avoided by the agency consulting with the Dev team early on and establishing a common set of tools to build with. But often the lack of un-opinionated, template and build-system agnostic tools means that component libraries get developed in a fashion that is inherently incompatible with the implementation environment.
We are certainly not immune from this at Clearleft, by the way. Previous versions of our in-house tool heavily relied on Twig, an (albeit excellent) PHP templating engine, but one which historically almost none of our clients used themselves; Of course they have full access to rendered HTML but the common step of clients having to re-template delivered HTML for implementation is one that we have worked hard to remove.
Integration is hard, so figure it out first
Without a doubt, figuring out how component libraries can integrate into the codebase or build process of the 'live' site is one of the biggest challenges related to this style of deliverable. It's not always required (or even desirable) but if it is, it probably needs to be the place you start your planning from.
The challenges that come up are often because of a separation of teams; one team building the component library (often the 'design team', either in-house or external) and another 'development' team who need to integrate the output with the main build. This in itself is not necessarily a problem; but working in isolation and chucking a component library 'over the wall' will never end well. The best technical solution for a tool for creating, previewing and documenting a component library is likely one that is well matched to the tools, languages and libraries used to build the site proper, and that takes a collaborative approach.
There are lots of potential ways to integrate a 'living' component library into the site - it could be part of the same codebase, with a separate 'preview' service for browsing components outside of the site context; it could be a separate entity that offers some sort of API for the main site to import components and assets; it could be some sort of export functionality that bundles up templates and assets from the library into a format more easily consumed by the production application; or any one of many other possibilities.
But regardless of the mechanism, the key thing is to make sure that discussions around integration happen before picking an off-the-shelf tool or planning a bespoke build. Integration is - in my experience - the hardest bit, so figure that out early on and then work backwards to spec the rest of your tooling from there.
More so than other deliverables, component libraries often end up being a focal point for many different disciplines - design, front-end development, back-end devs and even project stakeholders and the general public. How you build, maintain, integrate and provide a browse-able UI for your component library needs to be carefully considered if you are going to really match the needs of your particular set of circumstances well.
Taking some time at the start of any new project to really dig into the end-user needs of the library you are going to build will reap many benefits down the line. At the end of the day, the tool should get out of the way - make sure that all the hard work that goes into creating the components themselves does not get diluted by a system or tool that is poorly matched to its requirements or the the environment in which it will exist.