How To Use Storybook v7 With Ionic Framework And Angular
Tags: storybook, ionic, angular, javascript
Published: 2023-05-15 16:36:59

[Storybook](https://storybook.js.org/) is a tool that helps you develop and test your UI components in isolation. It can be used with any framework, but it is especially well-suited for Angular applications. In this blog post, we will show you how to set up Storybook version 7 to work with [Ionic Framework and Angular](https://ionicframework.com/docs/angular/overview).

> This blog post assumes you have already created your Ionic Framework Angular Project. See related video covering this blog post [here on YouTube](https://youtu.be/8rVCbD_8oDs)

## Setup
In your project directory run the command below to setup Storybook in your project
```
npx storybook@latest init
```

Now we need to modify the `angular.json` file in your projects root directory to include assets, styles and ionic icons in the project that Storybook will create for your Storybook stories.
```json
"storybook": {
  "builder": "@storybook/angular:start-storybook",
  "options": {
    "configDir": ".storybook",
    "browserTarget": "app:build",
    "compodoc": false,
    "port": 6006,
    "assets": [
      {
        "glob": "**/*",
        "input": "src/assets",
        "output": "assets"
      },
      {
        "glob": "**/*.svg",
        "input": "node_modules/ionicons/dist/ionicons/svg",
        "output": "./svg"
      }
    ],
    "styles": [
      "src/theme/variables.scss",
      "src/global.scss"
    ]
  }
},
```
### MemberCard Component
In [my sample project](https://github.com/aaronksaunders/storybookv7-ionic-angular) I have a component called `MemberCard` that I would like to create a story for and here is the code for the component template
```html
<div>
  <ion-card>
    <ion-card-header>
      <ion-card-title>{{ memberInfo?.name }}</ion-card-title>
      <ion-card-subtitle>
        <span *ngIf="memberInfo?.companyName">{{ memberInfo?.companyName }} : </span>
        {{ memberInfo?.title }}
        </ion-card-subtitle>
    </ion-card-header>

    <ion-card-content>
      <div>{{ memberInfo?.bio }}</div>
      <ion-item lines="none" class="ion-float-right">
        <ion-button
          *ngIf="memberInfo?.linkedIn"
          (click)="
            onClick.emit({
              event: 'social-clicked',
              value: memberInfo?.linkedIn
            })
          "
          ><ion-icon icon="logo-linkedin" slot="start"></ion-icon
          >LinkedIn</ion-button
        >
        <ion-button
          *ngIf="memberInfo?.twitter"
          (click)="
            onClick.emit({
              event: 'social-clicked',
              value: memberInfo?.twitter
            })
          "
          ><ion-icon icon="logo-twitter" slot="start"></ion-icon
          >Twitter</ion-button
        >
        <ion-button
          *ngIf="memberInfo?.website"
          (click)="
            onClick.emit({
              event: 'social-clicked',
              value: memberInfo?.website
            })
          "
          ><ion-icon icon="globe" slot="start"></ion-icon>Web Site</ion-button
        >
      </ion-item>
    </ion-card-content>
  </ion-card>
</div>
```
and this is the code for the component
```javascript
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { globe as globeIcon } from 'ionicons/icons';

export interface MemberInfo {
  name: string;
  title: string;
  companyName?: string;
  bio: string;
  twitter?: string;
  linkedIn?: string;
  website?: string;
}
@Component({
  selector: 'app-member-card',
  templateUrl: './member-card.component.html',
  styleUrls: ['./member-card.component.scss'],
})
export class MemberCardComponent implements OnInit {
  @Input() memberInfo!: MemberInfo;
  @Output()
  onClick = new EventEmitter<{ event: string; value: string | undefined }>();

  constructor() {}

  ngOnInit() {}
}
```

### MemberCard Story
I created my story by copying the sample `Button.story` and making the appropriate modifications. you can find your project's stories in the `src\stories` directory.

First you need to import your component, and then supporting modules
```javascript
import { MemberCardComponent } from 'src/app/member-card/member-card.component';
import { IonicModule } from '@ionic/angular';
import { importProvidersFrom } from '@angular/core'; 
```
Then you need to setup the story using the imported component. 
- The `title` is setup so that it will create a hierarchy with the toplevel being project and the new story `MemberCardComponent` as a child of Project
- `component` is the name of the component `MemberCardComponent`
- `render` set the type of the `args` to your component this ensures that the properties from your component get passed to story when it is rendered
- `argTypes` - the `MemberCardComponent` emits and `onClick` event when the user clicks on the social media buttons

The `decorators` property is an array of `decorators` that will wrap the story.
- `applicationConfig` is where we import modules that are needed for the Story.
- `moduleMetadata` the additional module information needed to support the component
- `componentWrapperDecorator` wraps the rendering of the component. In this case I am wrapping the component in the `IonApp` element
```javascript
const meta: Meta<MemberCardComponent> = {
  title: 'Project/MemberCardComponent',
  component: MemberCardComponent,
  tags: ['autodocs'],
  render: (args: MemberCardComponent) => ({
    props: {
      ...args,
    },
  }),
  argTypes: { onClick: { action: 'clicked' } },
  decorators: [
    applicationConfig({
      providers: [importProvidersFrom([IonicModule.forRoot()])],
    }),
    moduleMetadata({
      declarations: [MemberCardComponent],
    }),
    componentWrapperDecorator((story) => `<ion-app>${story}</ion-app>`),
  ],
};
```
For the actual stories, all you have left to do is create a `export` for each story, name it and pass it appropriate arguments. Here is an example of a story with all parameters passed in the `memberInfo` property called `Primary`
```javascript
export const Primary: Story = {
  args: {
    memberInfo: {
      name: 'Aaron Saunders',
      title: 'CEO',
      bio: 'Amazing Experience',
      companyName: 'Clearly Innovative Inc',
      linkedIn: 'Clearly Innovative Inc',
      twitter: 'https://twitter.com/aaronksaunders',
      website: 'www.clearlyinnovative.com',
    },
  },
};
```
To see how the UI for the component is rendered when missing the social media properties we have this story named `MissingSocial` you can see the code below
```javascript
export const MissingSocial: Story = {
  args: {
    memberInfo: {
      name: 'Aaron Saunders',
      title: 'CEO',
      companyName: 'Clearly Innovative Inc',
      bio: 'No news',
      website: 'www.clearlyinnovative.com',
    },
  },
};
```

### Running Storybook
```shell
npm run storybook
```

### Conclusion
In this blog post, we showed you how to set up Storybook version 7 to work with Ionic Framework and Angular. We also showed you how to create stories to test your UI components.

By following the steps in this blog post, you will be able to use Storybook to improve the quality of your Angular applications.

---

### Video
{% youtube 8rVCbD_8oDs %}



### Project Source Code
{% github aaronksaunders/storybookv7-ionic-angular %}

---

Please consider [signing up for our Newsletter​](https://buff.ly/3lAk2jL)