Storybook is a tool that allows to test an app's components in isolation and in a flat hierarchy. A storybook is a series of stories that display our components with specified inputs and outputs in a nice browser view.

Storybook has been getting really popular for React projects, and support for Angular and Vue projects was added with v3.3.0 so we can now just as easily use it for creating stories for Angular components.

Let's quickly go over setting up Storybook for Angular as well as basic usage.

Setup

storybook illustration for: Setup

Storybook now comes with a CLI tool that makes it really easy to add it to a project. First, install the <^>@storybook/cli<^> package globally:

				
					
# Yarn:

$ yarn global add @storybook/cli



# or npm:

$ npm i @storybook/cli -g

				
			

Now, in the root of an Angular project, run the <^>getstorybook<^> command:

				
					
$ getstorybook

				
			

This command will autodetect that it's an Angular project and will add the necessary configurations, devDependencies and npm scripts.

For example, at the time of this writing, the following devDependencies are added to the project:

				
					
"@storybook/angular": "^3.3.15",

"@storybook/addon-notes": "^3.3.15",

"@storybook/addon-actions": "^3.3.15",

"@storybook/addon-links": "^3.3.15",

"@storybook/addons": "^3.3.15",

"babel-core": "^6.26.0"

				
			

And the following npm scripts are also added to the project's <^>package.json<^> file:

				
					
"scripts": {

 ...

 "storybook": "start-storybook -p 6006",

 "build-storybook": "build-storybook"

},

				
			

You can now try it out by invoking the <^>storybook<^> npm script:

				
					
$ npm run storybook

				
			

This will start a local webpack server on port 6006 and you can visit the generated storybook by going to http://localhost:6006/. What you'll see is an example Storybook that was generated from an <^>index.stories.ts<^> file under a <^>stories<^> folder at the root of the project. Here's what the generated Storybook looks like:

The local server is equiped with webpack's Hot Module Replacement (HMR) so changes to your stories will be reflected automatically in your generated storybook.

You can have a look at the generated sample stories in <^>/stories/index.stories.ts<^> for an example of the syntax and API.

Your First Stories

Let's now create a simple <^>Card<^> component and a few stories for it to give you an overview of Storybook's usage. Here's our component's template:

				
					
[label card.component.html]

&lt;h1&gt;{{ title }}&lt;/h1&gt;

&lt;h2&gt;{{ subtitle }}&lt;/h2&gt;



&lt;hr *ngIf="title || subtitle"&gt;



&lt;p&gt;{{ content }}&lt;/p&gt;



&lt;button (click)="handleBtnClick()"&gt;Click me!&lt;/button&gt;

				
			

And here's our component's class:

				
					
[label card.component.ts]

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



@Component({

 selector: 'app-card',

 templateUrl: './card.component.html',

 styles: [

 `

 :host {

 text-align: center;

 background: white;

 display: block;

 padding: .45rem .65rem;

 border-radius: 3px;

 max-width: 325px;

 box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);

 }

h2 {

 color: #c85f7f;

}



p {

 text-align: center;

} `

 ]

})

export class CardComponent {

 @Input('title') title;

 @Input('subtitle') subtitle;

 @Input('content') content = '😄';

 @Output() btnClicked = new EventEmitter&lt;boolean&gt;();

 constructor() {}



				
			

As you can see, it's a very simple component that uses a few inputs and one output. We're also making use of the [:host](/angular/styles-between-components-angular/#host) selector to style our component's shell.

Now let's modify <^>index.stories.ts<^> to add a few stories for our card component:

				
					
[label index.stories.ts]

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

import { withNotes } from '@storybook/addon-notes';

import { action } from '@storybook/addon-actions';



import { CardComponent } from '../src/app/card/card.component';

storiesOf('Card', module)

 .add('empty', () =&gt; ({

 component: CardComponent,

 props: {}

 }))

 .add('with title', () =&gt; ({

 component: CardComponent,

 props: {

 title: 'Hello card!'

 }

 }))

 .add('with title and subtitle', () =&gt; ({

 component: CardComponent,

 props: {

 title: 'Hello card!',

 subtitle: 'Well hello there 👋'

 }

 }))

 .add(

 'with notes',

 withNotes('Just a few notes about this story...')(() =&gt; ({

 component: CardComponent,

 props: {}

 }))

 )

 .add('with action', () =&gt; ({

 component: CardComponent,

 props: {

 title: 'A card...',

 subtitle: 'Waiting to be clicked-on',

 btnClicked: action('👊 Button was clicked')

 }

 }));



				
			

Here are a few things to note:

  • As you can see, stories are created by chaining calls to <^>add()<^> on a call to <^>storyOf()<^>.
  • <^>add()<^> takes a name for the story and a function that returns an object with the component and props (inputs and outputs).
  • Actions triggered by outputs can be logged using the <^>action<^> addon.
  • Notes can be added to a story using the <^>withNotes<^> addon.

See this page for a list of other addons that can be used with Storybook.

For this example, I wanted the global styles of my Angular app to be reflected in the generated Storybook. It's as simple as adding a file called <^>preview-head.html<^> in the <^>.config<^> folder that's added by Storybook to the root of the project. In that file, you can add anything that would go into the head of a document. So let's add our global styles:

				
					
[label preview-head.html]

&lt;style&gt;

 body {

 background: #f3f3f3;

 font-family: Roboto, sans-serif;

 color: #6ba083;

 }

&lt;/style&gt;

				
			

...and here's what our Storybook now looks like:

Building a Storybook for Deployment

It's easy to generate a Storybook with static files that can be deployed to a static hosting service like Github pages. This allows to host a Storybook that other members of the team can easily consult.

Simply invoke the <^>build-storybook<^> npm script:

				
					
$ npm run build-storybook

				
			

It'll generate a <^>storybook-static<^> folder at the root of the project with all the files ready to be uploaded to your static hosting service of choice. You can also try it out locally using npx and <^>http-server<^>:

				
					
$ cd storybook-static

$ npx http-server

				
			

📙 The End! Read more about Storybook's usage in the official docs.