David Furnes is a software engineer based in Brooklyn, New York. 🎨

Pattern Libraries: The API for Your Stylesheets

How pattern libraries can decrease complexity & increase team velocity.

May be outdated! This note was last updated .

Pattern libraries exploded into popularity over the past couple years as a rebellion against confusing, mismatched designs & websites that become increasingly complex and difficult to maintain with age.

Two years ago, we found ourselves in that situation at DoSomething.org. When performing an audit of our existing stylesheets, we found repetition all over the place.1 It was hard to know where a particular rule would apply, and the only reliable solution was either duplicating code using new selectors, or applying skyrocketing specificity (hello, !important).

Development had slowed to a halt, so we declared bankruptcy and began to rebuild our CSS with a focus on maintainability. We rebuilt our site chrome in a fresh stylesheet, which we used when we redesigned our homepage in 2013.

Of course, most websites are never "finished". We knew it would only be a matter of time until our lean new stylesheet once again grew bulky & slow, unless we addressed the problems that led us there the first time around.

This meant changing how we worked.

A screenshot of Forge, the DoSomething.org pattern library.

We built Forge, our pattern library, as a weapon against cruft. It's a living design tool that we've maintained and expanded over the past two years. By building and cataloguing reuseable components, we've been able to keep our stylesheets under control even as our site continues to grow.

We write Forge components using Sass. Each component lives in a standalone file, like button.scss, named for its top-level CSS class. This helps prevent naming collisions & makes each pattern easy to find. Each file also begins with a KSS documentation block, which allows us to write comments that are automatically parsed into user-friendly documentation, published via GitHub Pages.

We distribute the final product as an npm module.2 This allows us to version our designs just like any other dependency. If we make a breaking change - where we'd have to change an application's markup - we can communicate that via semantic versioning. And, because we can "pin" dependencies in each application, there's no rush to upgrade everything at once.

Process

A pattern library is, first and foremost, a tool for building a healthy development process. It's a shared language for developers, designers, and product owners.

It makes developers' lives easier by allowing us to reference things we've already built, rather than reverse engineering previous solutions to match pixels in a mock. By encouraging developers to build & document reusable components, we make it easier to reuse than rebuild. This is true for designers as well!

Pattern libraries like Forge also make it easier to talk about design. Mocks – let's face it – are troublesome. Because they're a static canvas, it's easy to forget how dynamic the web is! Multiple screen sizes, hover states, and variable content all fall by the wayside. And because mocks start as a blank canvas, they encourage you to build everything from scratch every time.

Think of your pattern library as an API for your stylesheets. Just like an API hides complexity between different classes or services in your codebase, your pattern library is a interface that allows everyone to use interface patterns without necessarily understanding all the code behind the scenes.

Complexity

A pattern library is like "your own personal Bootstrap". But instead of a toolkit for building any sort of website, you're building specialized tools for building your website. So while Bootstrap includes grids, form styles, and some common elements like breadcrumbs, your own pattern library will include things that are more specific to your particular needs.

When building a pattern library for yourself, you're zeroing in on patterns in your own designs. What makes your website special? What unique challenges has your team had to solve? The easiest way to start building a pattern library is to look for things that you repeat in your designs.

Any project inevitably gets more and more complex over time. The goal of a pattern library is to avoid letting that complexity slow you down! You can keep nimble by limiting the number of things you need to be able to hold in your head to work on a project. Each component in your pattern library is an isolated solution to a problem your team faced when building your site.

Design & Architecture

A pattern library merges the domains of software design and software architecture. Think about the Single Responsibility Principle or DRY: it's not just about saving keystrokes; it’s about making sure you have a single representation of any logic you depend on. If styles are scattered about your codebase, it makes them hard to reason about or change.

To apply the Single Responsibility Principle to our stylesheets, we first identify and separate responsibilities. This means picking out pieces of a design that deal with things like layout, visual styles, or interactivity. A great example of this is Nicole Sullivan's media object – we found it everywhere in our designs. By encapsulating that layout concern into a reusable class, we're able to keep those implementation details in one place. We can then layer on visual styles or interactivity by composing this with other patterns.

We constantly make revisions to components – either for UX or visual improvements, or to fix bugs we've uncovered. When we fix a component, all of the pages that use it get that improvement for free. (And because each component has a single responsibility, we can feel safer updating and changing them without unintentionally breaking things!)

The Future

So how will we be building pattern libraries a year or two down the road?


React.js logo

It’s hard to talk about components without thinking of React, Facebook’s library for building the “view” layer of rich javascript applications. It touts simpler code through one-way data flow & a nifty Virtual DOM diffing algorithm that handles state transitions for you. And at its core is the idea of components:

"React is all about building reusable components. In fact, with React the only thing you do is build components. Since they're so encapsulated, components make code reuse, testing, and separation of concerns easy."

That sounds awfully familiar! Those components are your patterns.

With React's prop types, we can take our KSS documentation on how components should be used & automatically validate input. If an invalid argument is provided to a component, it will print an error to the web inspector.

About a year after React was introduced, Webpack entered the scene. Like RequireJS & Browserify, it lets you bundle your scripts into modules. But it also supports other types of assets through loaders. Using Webpack’s CSS loader, we can import our CSS class names directly into our React components.3

These are the missing pieces for building cohesive front-end applications! Together, these tools let you bundle everything for a pattern – markup, styles, behavior, and documentation – together in one place:

import React from 'react';
import classNames from 'classnames';
import styles from './button.css';

function Button(props) {
  var kind = props.kind || 'primary';
  var classes = classNames([styles.base, styles[kind]]);
  
  return (
    <button className={classes} onClick={props.onClick}>
      {props.children}
    </button>
  );
}

Button.propTypes = {
  kind: React.PropTypes.oneOf(Object.keys(styles)),
  onClick: React.PropTypes.fn,
};

export default Button;

And this isn't just about React! All the major web frameworks are moving to a components-based UI architecture. So no matter your stack, your pattern library will play a central role in how you build applications.4

Build things to help you build things!

Your pattern library is not the product. It's a tool to help make development easier by giving engineers, designers, and product owners a common language, and making it easy to document and reuse solutions to problems in the future.

Ultimately, this is about building things that help you build things. Your pattern library is a toolkit of battle-tested solutions to problems that your future self can reach for when they arise again.

Footnotes

  1. And we weren't alone! I love Brad Frost's concept of an interface inventory as a way of taming this sort of "design bloat". It's incredibly easy for designs to fragment, especially if you're working on a large website – or operating system – with a big team.

  2. And yes - this is a public package and repository! We open-source all of our code at DoSomething.org, including our production website. We've learned so much from others and want to make sure we give back. Feel free to poke around, make an issue or ask a question, or fork it as a blueprint for your own pattern library.

  3. The styles variable is a JavaScript object that exports classnames from our CSS file. Because Webpack knows all the classes we use in our application, it can automatically generate unique classnames for them as CSS Modules. It then outputs a “manifest” that maps all those optimized classnames to the human readable equivalents, which my component or app can use.

  4. Web standards are moving in this direction too – Web Components will introduce custom elements, template tags, & scoped CSS!