Angular & Storybook

Building & Documenting UI Components

Leonardo Giroto
Loft
10 min readSep 22, 2020

--

Storybook logo and article’s title: Angular & Storybook

"Storybook is an open source tool for developing UI components in isolation for React, Vue, Angular, and more. It makes building stunning UIs organized and efficient."

Storybook brings a lot of nice features out-of-the-box to aid us when working on UI components. It provides a sandbox to build them in isolation so we are able to develop them completely out of context. Therefore, we can test the multiple use cases in which it can be used and the different scenarios on how it can behave; making it easier to catch tricky edge cases.

Moreover, it also provides features that facilitates a lot to document those components. This makes it easier to share them with other teams and show how they can be used and when they should. It also supports Markdown and MDX which allows us to create robust documentation and style guides.

With Storybook you create stories for your components. Each story shows the behavior for a single component with specific states set.
Here we are going to see how to use Storybook in an Angular project and explore how it works and its functionalities.

Installing Storybook

Adding Storybook to an Angular project is pretty straight-forward.
First, we run the command below to install Storybook in our project, already initializing and configuring it.

npx -p @storybook/cli sb init --type angular

On our package.json we can see that some scripts have been added:

package.json file scripts

To run Storybook locally, just run:

npm run storybook 

We can also see that a /.storybook folder has been created on our root directory. These are configuration files for Storybook, where we should look for when changing global settings.

/.storybook folder files

obs: on Storybook’s main.js configuration file, you can see that it is set to look through the whole project for “*.stories.ts” files, so you can create your stories where you believe they better fit within your application.

It also adds a /stories folder which gives us some examples on the usage of Storybook, providing components that were built and documented with it.

/stories folder generated files

This is the base setup for Storybook and should be enough to get us started. We are going to look now into the process step by step, from creating a component, using Storybook to work on it and documenting it with it, while exploring its features.

Creating a Component

Here we are going to create a simple Link component; which is going to be a simple anchor with some custom styles, for learning purposes.

Let's start by creating it with Angular's CLI.

ng generate component components/link
link component’s generated files

Creating a Story

Now that we have our component created, we are going to create a Story for it. So let's create stories/link.stories.ts, like shown below.

link component’s files with stories file included

Following the initially generated examples, we can create our component's story, which is going to be like shown below:

import { CommonModule } from '@angular/common';
import { moduleMetadata } from '@storybook/angular';
import { Story } from '@storybook/angular/types-6-0';
import { LinkComponent } from '../link.component';
// This exports the Stories group for this component
export default {
// The title defines the name and where in the structure of
// Storybook's menu this is going to be placed.
// Here we add it to a "Components" section under "Link"
title: 'Components/Link',
// The component related to the Stories
component: LinkComponent,
decorators: [
// The necessary modules for the component to work on Storybook
moduleMetadata({
declarations: [LinkComponent],
imports: [CommonModule],
}),
],
};
// This creates a Story for the component
const Template: Story<LinkComponent> = () => ({
component: LinkComponent,
template: `<app-link></app-link>`,
});
export const Base = Template.bind({});
// Other stories could be added here as well, all you have to do is export them along!

Now we have our component and its story ready! When running Storybook, this is what this code is currently going to generate for us.

Storybook interface rendering raw link component

Working on our Component

Now that our component and its story is created, we will run Storybook.

npm run storybook

When Storybook is running, changes made to our component are going to be updated live and therefore we can work on it in an isolated manner and test its functionality and styles in the Canvas tab.

So first, let's give our component some properties:

// link.component.ts(...)export class LinkComponent {

@Input()
color: 'primary' | 'secondary' = 'primary';
@Input()
href: string;
@Input()
target?: '_self' | '_blank' | '_parent' | '_top' = '_self';

public get classes(): Array<string> {
return ['link', `${this.color}-link`];
}
}

Then, we change its template to render our properties.

// link.component.html
<a
[ngClass]="classes"
[href]="href"
[target]="target"
>
<ng-content></ng-content>
</a>

Lastly, let's add some styles to it!

// link.component.scss
.link {
text-decoration: none;
border-bottom: 1px dotted;
@media screen and (min-width: 600px) {
font-size: 1.15em;
}
}
.primary-link {
color: #ff4785;
border-color: #ff4785;
}
.secondary-link {
color: #1ea7fd;
border-color: #1ea7fd;
}

We also have to update our Story, so it reflects the new behavior we have developed for our component.

// stories/link.stories.ts(...)const Template: Story<LinkComponent> = () => ({
component: LinkComponent,
props: {
color: 'primary',
content: 'Visit Storybook',
href: 'https://storybook.js.org/',
target: '_blank',
},

template: `
<app-link
[color]="color"
[href]="href"
[target]="target"

>
{{ content }}
</app-link>`,
});
export const Base = Template.bind({});

And now we can check the final result in Storybook!

Storybook interface rendering link component

Exploring Storybook

There are some very interesting tools to help us when working on our component in the Canvas.

We can change the background color in order to simulate light/dark modes.

Storybook interface’s change background color icon

We can also toggle a Grid.

Storybook interface’s grid active

A very important one is the ability to change the viewport sizes, in order to verify the components behavior on smaller screens. For instance, it would come in handy for us to verify the changes on our component's font-size for smaller screens, as shown below.

Storybook interface’s change viewport size icon
Storybook interface’s with small mobile viewport selected

On the right corner, we have two interesting icons.
The first one, will expand the currently selected Story to full screen.
The second one, will open it in an empty iframe in another window.

Storybook interface’s focusing on icons
Link component’s story in an iframe

Installing Addons

"Storybook addons enable advanced functionality and unlock new workflows. Contributed by core maintainers and the amazing developer community"

Addons can provide a lot of useful functionality when developing and documenting with Storybook. In order to see how we can take advantage of them, we will install and use one of the most popular: the knobs addon.

"Knobs is an amazing resource for designers and developers to experiment and play with components in a controlled environment without the need to code! You essentially provide dynamically defined fields with which a user manipulates the props being passed to the components in your stories."

Let's begin by installing it in our project.

npm install @storybook/addon-knobs --save-dev

On Storybook’s main.js configuration file is where you register the addons and where we are going to add the new installed addon, like shown below.

// .storybook/main.js
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-knobs"
]
}

And now our addon is ready for use!
It is important to notice that the order on the addons array matters. For those who appear on the addons panel, the order will respect the order set there.

obs: you can check here the complete list of addons and choose the ones you want to install and use within your stories!

Using Addons

We are going to use the text and select of the addon-knobs.
They are going to set the value of ngContent and color props for our component dynamically when running Storybook.
Now, let’s open our component story and add the knobs addon to it.

// stories/link.stories.tsimport { withKnobs, text, select } from '@storybook/addon-knobs';export default {
title: 'Components/Link',
component: LinkComponent,
decorators: [
moduleMetadata({
declarations: [LinkComponent],
imports: [CommonModule],
}),
// we add the withKnobs decorator in order to use it
withKnobs,
],
};
const Template: Story<LinkComponent> = () => ({
component: LinkComponent,
props: {
// we use the select knob to set the color value
color: select('Color', ['primary', 'secondary'] , 'primary'),
// we use the text knob to set the ngContent value
content: text('Text', 'Visit Storybooks'),
href: 'https://storybook.js.org/',
target: '_blank',
},
template: `
<app-link
[color]="color"
[href]="href"
[target]="target"
>
{{ content }}
</app-link>`,
});
export const Base = Template.bind({});

With these, our knobs are successfully configured and we can check them out when running Storybook.

// The first parameter is a label for that knob
// The second parameter is its default value
text('Text', 'Visit Storybooks')
// The first parameter is a label for that knob
// The second parameter is the available options to be chosen
// The third parameter is its default value
select(
'Color',
['primary', 'secondary'],
'primary'
),
Storybook knobs addon interface

Now we can see that we have a new tab (Knobs) for our Story.
They come filled with the default values we have provided, but when we change them it will reflect dynamically in our rendered component!

It can be extremely useful when working on the component functionalities and styles, as well as when documenting it for others to test its behaviors.

Documenting the Component

We have our component ready and our story built, with addons configured for users to have a sandbox to play. However, sometimes we might need to share more information regarding our component; be it because it has more complex/not obvious functionalities, because we need to point to our users best practices on how to use, etc.

As shown in the Introduction.stories.mdx file that come with the installation, Storybook has support for .mdx files. With it we can build pages taking advantage of both markdown and html elements promptly. Therefore, we can easily use it to add some documentation to our component.

So, let's create a new file stories/link.stories.mdx, like shown below.

import { Meta } from '@storybook/addon-docs/blocks';<!-- This tells Storybook where to add this content -->
<!-- Here we want it along with our link component -->
<Meta title="Components/Link/Documentation" />
<style>{`
#colors {
margin: 20px 0px;
}`
`}</style>
# LinkLinks allow users to navigate to a different location.(... Lorem Ipsum ...)## Colors### Primary(... Lorem Ipsum ...)### Secondary(... Lorem Ipsum ...)

The content itself is just lorem ipsum for learning purposes, but below we can see what we could achieve with it.

Storybook interface showing link component’s documentation

Checking it out!

When we are done working we can generate our Storybook build by running:

npm run build-storybook

It is going to generate a static application inside the "/storybook-static" folder, which is ready to be published somewhere if you need to!

obs: when generating the Storybook build, it will create and output the compiled files to “/storybook-static” so don’t forget to add it to .gitignore.

You can check out the final code we have created here and also check the published version of it here!

Visual Regression Testing

When working on UI components, unit and snapshot tests are rarely enough since we are not catching visual regressions introduced due to style changes.
You can read more about it in this article.

Storybook is a great tool to be used along with visual regression testing tools. Most of them come with Storybook ready integration (like Loki, Percy and Chromatic, the last developed by the Storybook team) and generally it is very easy to be used with!

Storybook is a powerful tools that gives you a lot of amazing functionalities out of the box that can aid you when working on components. It can be very useful when sharing components between teams, building design systems and much more. Not only it helps with productivity, but allows you to have with little effort some documentation for them as well.

Hope it helps! 😉

References

--

--