How To Use Storybook with Ionic and ReactJS

Clearly Innovative
4 min readJun 18, 2020

Using Storybook for React with Ionic Framework is a great way to increase your efficiency and so much more if you want to build real component based solutions in your application.

You can quickly implement UI components along with validating the actions/events that the components respond to with out constantly rebuilding the entire application and repeating a set of action to get to the proper component on the proper page.

Here I will take the sample list application template and create a story around the message item component

  • move all events to parent component
  • add ability to have event for deleting the item
  • add ability to have event for favoriting the item
  • create a ‘decorator’ to handle the default Ionic App wrapper

Setup

Working with sample Ionic App with a list of messages.

First we install storybook; this will take a minute, be patient.

npx -p @storybook/cli sb init

Then open a new terminal window and start storybook, make sure you are in the root of the project directory.

npm run storybook

All the Ionic Stuff

Storybook has the concept of decorators which can be used to wrap the stories. So I created an IonWrapper decorator that has all of the code to setup a page and content in an Ionic App.

// .storybook/preview.js
import React, { useState } from 'react';
import { addDecorator } from "@storybook/react";
import {
IonApp, IonContent, IonPage, IonList, IonButton
} from "@ionic/react";
/* Core CSS required for Ionic components to work properly */
import "@ionic/react/css/core.css";
/* Basic CSS for apps built with Ionic */
import "@ionic/react/css/normalize.css";
import "@ionic/react/css/structure.css";
import "@ionic/react/css/typography.css";
/* Optional CSS utils that can be commented out */
import "@ionic/react/css/padding.css";
import "@ionic/react/css/float-elements.css";
import "@ionic/react/css/text-alignment.css";
import "@ionic/react/css/text-transformation.css";
import "@ionic/react/css/flex-utils.css";
import "@ionic/react/css/display.css";
const IonWrapper = ({ children }) => {
return (
<IonApp>
<IonPage>
<IonContent>{children}</IonContent>
</IonPage>
</IonApp>
);
};
addDecorator((storyFn) => <IonWrapper>{storyFn()}</IonWrapper>);

This allows me to keep the stories light and focus on just the content of the component I am working on

Setting Up Basic Story For MessageListItem

We need the basic imports for storybook and then we need to import the component that we are working with. We need to import IonList to ensure the IonItem in the MessageListItem is rendered properly.

Create the file, 2-MessageListItem.stories and start to add the following code:

// 2-MessageListItem.stories
import React from "react";
import { action } from "@storybook/addon-actions";
import MessageListItem from "../components/MessageListItem";
import { IonList } from "@ionic/react";

Set the default export for the story to using the MessageListItem component and create the first story

export default {
title: "MessageListItem",
component: MessageListItem,
};
export const BasicMessage = () => {
let message = {
fromName: "Andrea Cornerston",
subject: "Last minute ask",
summary: "Basic Message Summary",
date: "Yesterday",
id: 5,
};
return (
<IonList>
<MessageListItem
key={message.id}
message={message}
/>
</IonList>
);
};

I have mocked the data message to that we have some content to render in the ListItem, you should have the component rendering in the storybook web application.

Working On Component Actions

Storybook Addon Actions can be used to display data received by event handlers in Storybook.See documentation

Let’s set the component up properly so there is no business logic handled in the component, just responding to actions and passing the actions up to the parent.

First the Click Event On The Item

Modify the properties that are passed into the component to also include the click event which is called when the item is clicked. We want the function to return the message object that was clicked.

// src/components/MessageListItem.tsx
interface MessageListItemProps {
message: Message;
handleClick: any;
}

We will change the IonItem to handle the event

// src/components/MessageListItem.tsx
<IonItem onClick={()=>handleClick(message)} detail={false}>
... OTHER CODE ...
</IonItem>

Now back in our story, we can use the action add-on to handle the response from the click event to know it is working properly

// 2-MessageListItem.stories
<IonList>
<MessageListItem
key={m.id}
message={m}
handleClick={action("item-clicked")}
handleFavorite={action("option-handleFavorite")}
handleDelete={action("option-handleDelete")}
/>
</IonList>

HANDLE CLICK ACTION

Handle Item Option Events

One way to handle multiple actions on a List Item is using the IonOptions that are displayed when you swipe the item. In this example we will support deleting the item or adding it to you favorites. Once again we want to keep this component simple and have the parent respond to the event.

Lets add the additional properties to the component

// src/components/MessageListItem.tsx
interface MessageListItemProps {
message: Message;
handleClick: any;
handleFavorite: any;
handleDelete: any;
}

We will change the IonItem to handle the events and once again pass back the associated object

// src/components/MessageListItem.tsx
<IonItemSliding>
<IonItem
onClick={()=>handleClick(message)}
detail={false}>
... OTHER CODE ...
</IonItem>
<IonItemOptions side="end">
<IonItemOption
onClick={() => handleFavorite(message)}>
Favorite
</IonItemOption>
<IonItemOption
onClick={() => handleDelete(message)} color="danger">
Delete
</IonItemOption>
</IonItemOptions>
</IonItemSliding>

Now when we click the options we get the corresponding events and properties displayed in the actions area in storybook.

Delete Action

Favorite Action

The source code can be found here

https://gist.github.com/aaronksaunders/7db8d84555f1a736a2777825ec8bca73

--

--

Clearly Innovative

DC based software agency utilizing #Javascript, #HTML5, #Ionicframework, #VueJS , #ReactJS to build solutions. https://www.youtube.com/@AaronSaundersCI