Cooking with Design Systems

Design systems make deciding in the browser much easier if you have the right ingredients.

Published on

Around 8 minutes to read

A great design system should equip you to quickly and confidently create delicious user experiences. Creating a great design system is a lot like stocking a very specific kind of kitchen.

Let’s say I run a food truck. I have a small kitchen in said truck, so I need to be judicious in what ingredients I stock. To determine the right ingredients to bring along, I can ask myself a few simple questions:

  1. What dishes will I definitely make? What ingredients do I need to make those dishes?
  2. What dishes might I make? What ingredients do I need to make those dishes?

What’s on my menu? If I run a Mexican street food truck, I’ll have main dishes like tacos, burritos, and quesadillas. I’ll have a few appetizers and sides like street corn, empanadas, and chips & salsa. But, I’ll also need the ingredients that make those mains and sides, even if they’re not specifically listed on my menu—lettuce, tomatoes, cabbage, mayonnaise, salt, pepper, paprika, avocado, rice, jalapeño peppers, tortillas, tomatilos, oregano, cilantro, cheese, etc. These are all the things I’ll need to bring with me onto the truck.

Part of what’s important in what I’m bringing is also what I’m not bringing. Dill and cinnamon are great spices in general, but I don’t plan on making anything with them, so I can leave out for now. (And I can always change my mind later.)

If I’ve been running my food truck for a while, I know that some dishes will almost always get ordered, so I can prep them in advance. I can start cooking rice. I can chop lettuce and cabbage. I can set up my mise en place so that it’s ready for use when customers start ordering.

I can get some headstarts too. I can throw a cup of salsa and a handful of chips into a bag and seal it; no more assembly required. I can also pre-cook beef with onions, spices, and marinade to be ready to throw into a taco or burrito. This one needs to be finished with a tortilla and some veggies, but I don’t need to start from scratch everytime someone orders a beef dish.

It’s helpful for me to think about these things in categories:

Turns out this is also a pretty good model for organizing a design system.

Even though many have been using these phrases for years, you can tell it’s still early days regarding things like “design systems,” “component libraries,” and “style guides” because we can’t yet get the words right. Everyone insists that they’re different, but we still use them interchangeably. Canonical definitions for each have yet to emerge. Until they do, I’ll use the ones that best fit for and most appeal to me.

Graphics editors like Photoshop and Sketch allow you—but also force you—to create everything from scratch. A strict component library might encourage you to only use the components as they come without any customization; a good example was Flash’s component library (Bueller?). Design systems fit somewhere in between. A design system is the smallest set of tools to help me effectively create what I need.

It’s worth mentioning that graphics editors and component libraries aren’t mutually exclusive. Most examples in the wild aren’t purely one or the other, or at least easily convert closer to the certain. Add a UI Kit to Sketch and it gets closer to a design system. Add some spacing and sizing tokens to a component library and it gets closer to a design system.

Testing a design system’s efficacy is easy on paper: can you easily create what you intend to? Back to our metaphor, can I quickly make a delicious burrito? Like a well-stocked but limited kitchen, a good design system is a combination of raw ingredients and headstarts to make delicious dishes. It’s as many of these things as you need, and no more.

I wanted to create and maintain this site primarily with a design system—not a graphics editor or a component library—so I brought along a limited pantry:

How did I decide what’s what? I’m glad you asked.

Prolific designer Milton Glaser said, “I move things around until they look right,” Because that’s most of what I do in Photoshop and Sketch, I need a way to do that in code.

First, I need to make the “things” that need to be moved around. That means writing the HTML I need as semantically as possible.

Then, I started to build some “move around” tools. I’m a big fan of how Harry Roberts suggests organizing CSS for maximum maintainability, and I just wrapped a project with Brad Frost and Ian Frost where we used with a similar CSS architecture. I also wanted to try out the 8-point grid that all the kids are raving about.

I created some variables so that I can change spacing globally if the 8-pt thing doesn’t work out.

$spacing: 8;

$xs: $spacing;
$s: $spacing * 2;
$m: $spacing * 3;
$l: $spacing * 4;
$xl: $spacing * 5;
$xxl: $spacing * 6;

Next, some spacing mixins:

@mixin sf-u-margin--0 {
  margin: 0;

@mixin sf-u-margin--xs {
  margin: $xs + px;

@mixin sf-u-margin--s {
  margin: $s + px;

@mixin sf-u-margin--m {
  margin: $m + px;

@mixin sf-u-margin--l {
  margin: $l + px;

@mixin sf-u-margin--xl {
  margin: $xl + px;

@mixin sf-u-margin--xxl {
  margin: $xxl + px;

A few notes about that:

I also duplicated those mixins in a utilities.scss file so that I could use them in both HTML and CSS:

.sf-u-margin--0 {
  @include sf-u-margin--0;

.sf-u-margin--xs {
  @include sf-u-margin--xs;

.sf-u-margin--s {
  @include sf-u-margin--s;

.sf-u-margin--m {
  @include sf-u-margin--m;

.sf-u-margin--l {
  @include sf-u-margin--l;

.sf-u-margin--xl {
  @include sf-u-margin--xl;

.sf-u-margin--xxl {
  @include sf-u-margin--xxl;

It’s not as DRY as I’d like it to be, but I’m happy to trade principle for the pragmatism of moving quickly in code.

Once I feel like I have a thorough enough set of raw ingredients, my goal is to create as much of the site as I can without opening my stylesheet again. If I can do this, I’m using my design system, as opposed to creating patterns on the fly.

Let’s do an example: a basic article page. I’ll start by creating the title of the page:

<h1>Cooking up Design Systems</h1>

I’d like to style this headline to be somewhat large, have a little space on the left, and have some room below. Without a design system, I might create a new class and write some new styles, but remember: I want to use my design system and not add anything new to my stylesheet. So, I’ll use some rules that I’ve already created:

<h1 class="sf-u-padding--l sf-u-margin--xl sf-u-font--l">
  Cooking up Design Systems

This style of coding certainly isn’t new; many frameworks like TachyonsAtomic CSS, or Expressive CSS have suggested this for a long time. The biggest criticism of this approach is that it isn’t much better than writing inline styles, and you lose a lot of the benefits of the cascade that made CSS so powerful in the first place. True, at first glance, it doesn’t look much different than:

<h1 style="font-size: 40px; padding-left: 24px; margin-bottom: 32px;">
  Cooking up Design Systems

But I’d argue that there are still a few benefits:

You get an even bigger benefit if you take this a step further. Let’s say you create 3 more of these headlines. Congrats! You’re on your way to a bona fide pattern! This is where I’d crack back open my stylesheet, not to write more styles but to codify the pattern.

First question: is it a content pattern or a display pattern? It’s a bit too specific to apply to a particular type of content; calling this a articleTitle may make me think twice about using this on the Contact page. Display pattern it is! We’ll call this our bigTitle. I’ll use a dp- prefix to mark it as such. So, the HTML turns into:

<h1 class="sf-dp-bigTitle">Cooking up Design Systems</h1>

In my stylesheet, I’ll create a new rule for my new display pattern, but instead of writing custom declarations, I’ll instead use my existing mixins, cut-and-pasted directly from my markup. Again, I want to use what’s already in my design system, keeping things as DRY as I can. That rule would look like this:

.sf-dp-bigTitle {
  @include sf-u-text--xl;
  @include sf-u-paddingLeft--m;
  @include sf-u-marginBottom--l;

That way, I’ll almost always know at a glance as I skim my stylesheet what parts use the design system I’ve established and what parts deviate.

Last thing: I like to leave some space at the bottom of every rule for “seasoning.” In cooking, there’s this phrase called “season to taste,” which means that you can continue to add spices and herbs if a dish doesn’t taste perfect when it’s done cooking. It might not be part of the recipe, but you need it in this specific instance. In the case of code, that might be applying a background color to an element or adding a particular animation:

.sf-dp-bigTitle {
  @include sf-u-text--xl;
  @include sf-u-paddingLeft--m;
  @include sf-u-marginBottom--l;

  // seasoning
  background-color: gold;

Again, you can quickly visually identify what parts of this block are part of the design system, and which is some extra seasoning. After noticing that you’re writing background-color: gold; 4 or 5 different times, then you can consider adding it permanently to your design system as a utility and/or mixin.

Hopefully, this example showed how you can bring some of the UI decision-making process you previously did in a graphics editor into the browser, as long as you have the right code approach to support it.

Now you’re cooking!

Read Next


Join 48,700+ subscribers to the weekly Dan Mall Teaches newsletter. I promise to keep my communication light and valuable!