Creating and maintaining patterns in PatternLab

I started writing this article a good while ago (two years ago now), and I was about to publish it at the beginning of 2019. But as it was nearing completion, life happened, and only now I'm picking it up again and finally publishing it.


I have worked in PatternLab for quite some time now, even more so with style guides and pattern libraries, and I have noticed that after a while, creating new meaningful patterns, maintaining, and improving the existing library can be quite daunting and challenging.

Creating a pattern library alone needs an incredible commitment and dedication, and its inception can be particularly stressful.

I've seen this somewhere else, but I can probably help visualise the investment to explain what I mean:

img plotting things on a graph

The graph is based both on factual evidence and some data, like commit frequency, and code changes.

Because of this, I cannot stress enough that:

if you want to tackle the problem of pattern libraries, you'd better not be alone.

What follows in this article is pretty much subdivided into the following two main topics:

  • The preparatory phase: anything that can help before starting to work with PatternLab.
  • The during and post-delivery phase: anything that you can do to help yourself now and later on.

Most of what I'll be talking about is mostly gravitating around PatternLab, as it's the primary tool that I've been using, hopefully helping me conclude the series of articles I've written so far about it.

You need some working knowledge of it, many terms I'll be using are specific to it, and the same goes for Atomic Design methodology. But if you've worked with PatternLab, you should have an idea of how it works, at least roughly, and that would be enough.

I also hope that what you'll be reading about here can be easily applied in a much more practical way to any other tool, because

tools change, so don't cling on them.

Enough chit-chat, let's move on.

The preparatory phase

These are a quick summary of methodologies that I have noticed directly or indirectly could help mitigate the fatigues you might experience later on when starting to work on the library and maintaining it.

Rome wasn't built in a single day

And I want to start start with methodologies, or otherwise guidelines.

Guidelines

Guidelines end up making the most generic recommendation I can give, but you can't have enough of this: as with everything you need boundaries to work within.

If you work with someone else, like in a team, this is even more relevant.

Using well known and established guidelines and methodologies is probably the best approach you can have to keep things tidy and straightforward. The best approach I can recommend is Atomic Design.

As I tried to explain in a previous post of mine about CSS architectures for UI developers, there are many layers to this, and you should confront yourself with the reality of picking the most simple and well understood by your team.

Spend time making sure everyone is on the same page, as that's how you make sure people can contribute positively, and you can post any problems with it.

It doesn't mean that you can't roll your own. That's where most, if not all the project I've worked on ended up.

Take, for instance, WeWork's (RIP) Plasma Design System and notice that they use a super-simplified organisation, made of Foundations, Components and Patterns. As in Atomic Design, they have a space for Templates and Pages, but that's another story.

Semplification of Plasma structure

The path that led General Electrics into what is now the Predix Design System is a beautiful and clear explanation of the (tortuous perhaps) journey that took them there, you can read more about it in the article written in 2017 by Ken Skistimas.

You can read more on this topic on Alla Kholmatova's book Design Systems, which is probably the best on the topic.

Design Tokens

Amongst the guidelines you should probably look into, I'd strongly recommend having a grasp of what Design Tokens are and try to start extracting them out of your preliminary work.

Currently, I consider Design Tokens the core of a design system.

Design Tokens have been talked in the last few years quite a lot, and I think the single most critical article for me has been the one written by Cristiano Rastelli: Managing Design Tokens with Style Dictionary.

Design Tokens express how you encode components and build them.

The physical output can be something like a SCSS file and/or a JSON file that is readable by JavaScript.

Without diving straight into something that can be complicated like Style Dictionary, you can start with something simple as Theo, or even simpler, like your SCSS file. The critical part here is how to extract the variables that make up your components and how to name them. Importing this file into PatternLab can be quite straightforward, so the overhead should be almost minimal later on.

Build and post-delivery phases

Now that we've taken care of the initial steps, it's time to look at what can help during the build and post-delivery phase.

The mantra that would be useful to repeat during the build phase is:

make things reusable.

Once we've established that the code is the primary source of truth for the patterns, the main concern now should be to reduce the overhead as much as possible, so we can concentrate on designing and implementing them.

You want to exploit as much as possible the templating languages used in PatternLab, and any additional functionality PatternLab provides on top. I'm specifically talking about these base functionalities:

  1. being able to include and reuse patterns (i.e. templates),
  2. being able to pass variables to patterns and customise their behaviour and state,
  3. being able to generate any additional documentation,
  4. being able to generate code for more comfortable distribution (e.g. with other templating engines).

The first two are essential to work in a DRY way, while the last two are incredibly beneficial to improve the adoption of the pattern library.

Where to start from

There are no rules here, and it can depend on whether we're starting from an already existing pattern library and design system, or if we're starting from scratch with something completely new, as taking an existing design and converting it conveniently in a design system or pattern library.

Consider this: when we start implementing our pattern library, we need to reach a critical mass of smaller components to be able to see them being used appropriately and being able to compose our first few pages or sections. By not doing this, we risk to forget some of the basic patterns and instead put much effort when creating more significant components.

In this initial phase being able to identify all the smaller components is essential. I would strongly recommend the participation of both a developer and a designer from this point on.

I would also like to discourage creating single separate templates for each of the atoms: the experience has taught me that these are hard to remember, hardly maintained, and cause many problems when parametrising them for template inclusion sake within PatternLab (and this applies as well to other style guide tools). Nonetheless, we do want to have these styles ready available on a global level (there are some caveats, but more about these exceptions later).

Default HTML elements

Given your basic Design Tokens are already in the library, we shouldn't be worrying about them anymore. We are going to create more of them, but that's a given.

We now want to take out of the equation all the basic elements that we might need to use. The demo site of PatternLab can give you a good idea of that:

  • block elements, e.g. img , p, lists, headings.
  • inline elements, e.g. a, strong, em, and anything else that comes into mind.
  • form elements, e.g. the various input types, buttons, and anything else needed.

Not every website needs form elements, but usually, buttons are quite useful when taking user interaction into account (unless you're OK in just using anchor elements). Prioritising them can also help to release earlier.

All of these can be easily grouped into a single template into PatternLab, rather than each one being a separate template, as suggested earlier once this section starts to grow enough (you decide when), it could be a good thing to split it up in more digestible bits.

Once again, these templates are usually not needed for inclusion, but more for documentation purposes, while all these elements can be used natively across any other template.

You might have noticed that some style guides do not display some of these by default, instead preferring either a "book page" to show a few things put together, or by showcasing only the form elements, effectively prioritising the display of what is essential on the current use case.

This section should also make you question the way you've modularised the design: finding which should be the default font styles throughout your application is essential. Remember that you want to override these basic styles only when strictly needed.

Avoid making the exception a rule.

To get an idea on how to deal with exceptions and experimenting with new things, Brad Frost wrote an excellent article about the workshop and the storefront which I greatly recommend.

Custom atomic elements

At this point, we've taken care of all the necessary things, if not the most important ones. Now it's time to focus our attention on custom elements.

Atoms, as per Atomic Design terminology, are not necessarily single tags, in HTML terms. I've always found it useful to consider atoms the most straightforward and smallest component. I don't think there's a right way to do this, if not what works for you.

Once again, they can be represented collectively in a macro section within PatternLab, which means that we are going to write the markup manually in Molecules and Organisms as needed. This organisation should give us a bit more flexibility without having to code many conditions on when to display specific state modifiers or, even more so when overloading variables.

Organising variables and overriding them

Organising variables and understanding how to make proper use of them within PatternLab has been one of the trickiest parts I've encountered.

As you might already know from the documentation about data, the /source/_data/data.json file contains the source for all global variables. The cool part about PatternLab is that it offers some sort of inheritance; in other words, a way to override the data defined in the global data file. This method for overriding variables allows creating patterns that reflect use case scenarios more closely when used in conjunction or within some other pattern while having a more generic copy when displayed in isolation.

When the pattern library starts to grow the possibility to have different names of variables can happen, eventually leading to global namespace pollution, this situation can quickly grow out of hand and lead to problems of maintainability.

As a way to mitigate, you can easily namespace all variables within a particular pattern.

For instance, let's imagine we have a card template, that requires a title and some generic paragraph copy. The basic approach is to have something like the following:

<div class="card">
  <h2>{{title}}</h2>
  <p>{{description}}</p>
</div>

the data.json usually looks more or less like this:

{
  "title": "Amet porro voluptates atque architecto et id non",
  "description": "Esse aliquam id distinctio vel. Repellat illo fuga commodi libero iusto. Blanditiis quo debitis voluptate molestiae ab. Voluptas inventore vel totam veritatis."
}

Now, if we start using the card within another template that uses title and description as well, or where we want to use a different copy for these two fields to give more credibility in the context, or even when we want to iterate and generate a list of cards, you might want to namespace the variables:

<div class="card">
  <h2>{{card.title}}</h2>
  <p>{{card.description}}</p>
</div>

which allows you to have the following two data structures:

{
  "card": {
    "title": "Amet porro voluptates atque architecto et id non",
    "description": "Esse aliquam id distinctio vel. Repellat illo fuga commodi libero iusto. Blanditiis quo debitis voluptate molestiae ab. Voluptas inventore vel totam veritatis."
  },
  "cards": [
    {
      "card": {
        "title": "title card 1",
        "description": "A very short description for card 1"
      }
    },
    {
      "card": {
        "title": "title card 2",
        "description": "A very short description for card 2"
      }
    }
  ]
}

with card you populate the stand-alone template, while with cards you can populate a list of cards like the following:

<ul class="cards">
  {{#cards}}
    {{>molecules-cards}}
  {{/cards}}
</ul>

the above allows us to have full control of the content and the variables alike.

As a suggestion, I'd recommend to always start from some generics variable names. Try not to rely too much on them, instead move into a namespaced data structure as soon as you can do so.

Adding and maintaining patterns in PatternLab

After a while, the pattern library might have grown quite a bit.

At this point in the story, I've always started to hit the most significant problems:

  • adding loads of slightly different patterns, all similar but fundamentally different,
  • splitting up many patterns for infinite compositions.

These two case scenarios are prevalent. They're even familiar in modular systems without even taking pattern libraries into account. And they're both the symptom of something wrong.

Usually, we can address the first case with the introduction of state modifiers, but it's not always possible, as sometimes is not an actual "state".

If you find yourself implementing something that has got an incredible resemblance of something else that is already in the system, you should ask yourself why the developer hasn't talked to the designer already and sat down with them in front of the code to find a better solution or a workaround to that. Lists, for instance, tend to fall into this category.

Sometimes this has already happened, and maybe you've been lucky. A treacherous road I've seen used is to try to split everything into small composable classes. But unless if you're building a multi-purpose fit-all framework, this is not the right way to take: by doing so we're depriving the system of intent, we're extrapolating the concept from the domain, abusing it without real purpose. Oh, the number of times I've seen compositions that shouldn't have been there with overrides to fix some weird looking styles.

I do believe there must be a balance between the number of reusable elements you can have and the single-purpose ones.

Depending on the system we're working on, we can take care of these problems by using functionalities provided by frameworks or tools, for instance, with the use of mixins in SASS. Even then, I've never seen these as the cure for everything, and as it turns out, it's mostly a question of agreeing on a standardised approach on the way we use a particular tool, making sure everyone's is on the same page and following it.

Final Notes

I think there should be more to this, so please feel free to contact me or comment here if you want to read more about the topic.

At the same time, I'd encourage you to participate and contribute to PatternLab, by submitting bugs, improving the documentation and talking to the people that are using it.