Building a Design-Driven Workflow in Storybook.js with Angular and Sketch – Part 1

Crafting a good and consistent user experience for your product is hard work and requires a lot of dedication. Therefore setting up a bullet-proof workflow that keeps everyone in the team in the right mindset is key.

What we’ll be doing

The goal of this series is to give you an idea of what Storybook is and how to set it up in your Angular project. I’ll go into a bit of detail about why and how I think this process helps in creating a shared context for your team, as well. At the end of this post, you’ll have an instance of Storybook up and running, wired up to your Angular project.

For your convenience, I’ve prepared a GitHub repository that you can check out, if you don’t want to type all the examples in this post yourself. You can find the repository here: https://github.com/kaeku/storybook-workflow-blog-post

Assembling A Team

The most crucial of every good design workflow is getting everyone on board. A lot of confusion, redesigns and respeccing can be easily avoided by offering everyone a seat at the table in the first place. I, for one, like to invite at least one member of each department to my UX workshops. Now, this might sound like endless discussions and disagreements to you at first. But the reality is, if you respect everyone equally and treat their opinions with the importance they deserve, you are going to find lasting consensus quite easily.

Removing Layers of Abstraction

Most of the projects I’ve worked on in the past used an established setup, keeping everyone working on the visual parts of the product in their respective tooling comfort zone:

  • Designers: Sketch/Figma/Adobe XD, InVision or Sketch Cloud
  • Frontend Developers: discrete styleguide in plain HTML and CSS with some kind of preprocessor, some kind of single page application

So what’s the problem here, you might ask? Well, the answer is: If the process is working out for you, you’re good to go. For small teams, this usually means you have one designer teaming up with two to three frontend developers.

For me, this usually meant being some kind of bottleneck and/or single point of failure. I’d prepare prototypes in Sketch, based on the specs we wrote out. Maybe I’d even build prototypical components in HTML and CSS, then someone would pick those up and transport them over to Angular.

However, once there was a lot of things to do on the design-end of things, the JS devs would lack the styling input and had to step in to do some styling work. Even if the pipeline was running smoothly and the styles kept on coming, we’d still face the never-ending back and forth cycle of keeping the HTML prototypes in-sync with the application architecture.

This process felt rather tedious in the long run, and I found it relying too heavily on one person. So, what can we do about that?

Sharing Context

Let’s be honest, though. Nobody wants to be the limiting factor in a team. This only leads to yourself trying to fit everything in and quickly being overwhelmed and overworked. Splitting the workload and having everyone involved leads to a healthier work environment and we get the benefit of collaborative design for free – that’s a classic win-win situation!

In order to get everyone on board, though, you will have to create a welcoming environment and move out of your comfort zone. The way I went about this, is to think about everyone’s needs and find the sweet spot. The point where our needs overlap. Let’s see what this meant for my time, then:

  • Developers: automate as much as possible, don’t repeat yourself (DRY), work with real data right ASAP
  • Designers: create sophisticated designs, test different iterations of a component, don’t want to get involved with the technical in’s and out’s too much

Alright, great! No we know what we need. Some kind of cradle for all the application’s parts that we use to design, develop and test the components with. This may sound quite daunting at first, but bear with me here.

Progress is Iterative

Now, you’ve figured where you as a team want your sweet spot to be. The workflow is laid out, you’ve drawn some fancy diagrams to convince your boss — in short, you’re ready to hustle. Chances are, though, you can’t refactor the whole project and lock yourself in for the next few months.

Crafting a good and consistent user experience for your product is hard work and requires a lot of dedication.

But don’t worry! We can do this, step by step. Even in a very cost-effective and non-blocking manner. The nice thing about the workflow I’m going to introduce here is that you can drop it into your project and get working on new features right away. And if you do have the time to refactor and rebuild, you can do that as well. The main thing to remember here, though, is that we’re in for the long run. Remember: Crafting a good and consistent user experience for your product is hard work and requires a lot of dedication.

Setting Up The Workbench

The tools I found to be most effective for our workflow were Sketch and Storybook. Sketch is giving me the freedom to design highly reusable and sophisticated components (or Symbols, as it’s called in Sketch), while Storybook plays well with most of the big players in the JavaScript/SPA framework market. You can think of Storybook as the visual test bed for components. New and existing components can be dropped into Storybook and you can specify each and every small use case there is. This paves the way for building your design system, step by step – without creating much overhead.

Using Storybook in an existing project

The short route: @storybook/cli. This sets up storybook automagically through the Storybook CLI. This approach is fine if you want to go with default Storybook setup. However, I’d recommend tweaking this config ever so slightly, so you can put the .stories.ts files next to your components — just like you’d most probably do with a unit test. You can still use the CLI to do the grunt work, then we will just tweak the config a bit. To get started, navigate to your project and run npx -p @storybook/cli sb init. Once this is done, we will go to .storybook/config.js and change the following line:

const req = require.context('../src/stories', true, /\.stories\.ts$/);

to this:

const req = require.context('../src', true, /.stories.ts$/);

Now we don’t need to create a separate stories folder, but can rather add those stories in their respective component’s folder. You should now be able to do a npm run storybook and see your very own Storybook instance in the browser. Awesome!

The full config.jsfile:

import { configure } from '@storybook/angular';

// automatically import all files ending in *.stories.ts
const req = require.context('../src', true, /\.stories.ts$/);
function loadStories() {
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);

Creating Your First Story

Now that we have our basic setup up and running, we will want to add a first component to test with Storybook. For this, we will add a simple input.component.ts:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-input',
  templateUrl: './input.component.html'
})
export class InputComponent {
  @Input() public label = 'Label';
  @Input() public placeholder = 'Placeholder';
}

In this component we specify properties for a label, placeholder and the disabled state of the input. These are the properties we want to test in our first story. We will also add a template called input.component.html to apply those properties:

<label for="input">{{ label }}</label>
<input type="text" id="input" [placeholder]="placeholder">

And now we get to the good parts – testing the component. In order to do so, we will add a input.component.stories.ts file right next to our component and write our first story. We’ll start with defining a story:

storiesOf('Input', module)

Now we’ll want to define our use-cases by using the .add function. For our most basic use-case, we will add a Default-story, that just pulls up our component.

.add('Default', () => ({
    component: InputComponent,
}));

Once you run npm run storybook, this will pull up Storybook with the component we just created:

Testing Your Component With Data

Now this is where Storybook really shines. Once you’ve got a component running, you can test each and every use case for it. With knobs you can even empower your team to test edge cases by entering data themselves. Knobs are a way to enable the user to experiment and play with the component through a visual interface right inside Storybook. They can be hooked up to the components’ inputs, making it possible to change the inputs’ values in real-time.

For the projects I’m working on, I like to create stories for most, if not all, of the use cases that appear in the live project. With the props property of the story config object you’ll also be able to provide mock data to your component. When we tie these two together, we get a neat testing interface for our component. To do this, we will define a new story for a disabled state of our component. So, first of all, let’s extend the input component to have an input for the disabled property like so:

@Input() public disabled = false;

We’ll also want to test this newly created property with a story – after all, that’s we’re here for. Right?

  .add('Disabled', () => ({
    component: InputComponent,
  }))

Just like with our very first story, we will define a name for our story and specify which component we’re going to test. Once that’s done, we can go right ahead and throw some properties in the mix.

  .add('Disabled', () => ({
    component: InputComponent,
    props: {
      label: 'The disabled label',
      placeholder: 'The disabled placeholder',
      disabled: true,
    }
  }))

Once Storybook refreshes, you should be able to see your new test case called Disabled in the sidebar, grouped under the input component. Also, our label and placeholder should change, since we specified different values for those properties. With the props object, we can directly address the Angular component’s inputs and play around with our live component. Neat!

The “Convince Your Boss Kit”

So now you have created your very own Storybook. But what should you tell your boss to get him to greenlight this effort for your project? Here’s some reasons why you should be using Storybook in your project. Developing components with Storybook:

  • provides an easy way to test edge cases, which would usually be hard to reach and keep track of in your live application
  • lets you present different aspects of a feature in a clear and easy to understand manner once it’s deployed somewhere
  • enables you to test those components right away without being dependent on other business logic, data or component hierarchies
  • paves the way for unit testing, since you already have mock data and testable components at your disposal
  • gives everyone in the team a shared context to talk about.
  • makes reviewing features easy
  • helps you avoid regressions, especially when you implement automated testing
  • provides a common place for everyone in the team to experiment and play with the components

Wrapping Up

That’s it for this part of the series. By now, you have successfully setup your first Storybook inside your very own project. You did great! In part 2, we will talk about making your new workbench more accessible by extending Storybook’s default feature set.

Have you tried this workflow and are keen to share your experiences? I’d love to hear from you on twitter!