This is a quick overview as a companion document to video tutorial linked below.
We will create a story for a LoginForm component with two input fields that emits events for login and create account.
There are a few extra steps that you need to follow to get your Ionic Vue project working together with Storybook and luckily once you get Storybook project configure for your first story, you are good to go for the remainder of the stories you create.
Lets Go
Install storybook at the root of your project and launch it.
npxsb@nextinit
npmrunstorybook
We need to add the ionic styles to .storybook/preview.js so that we get the look and feel along with the default theme applied to all of the stories in the project
/* Core CSS required for Ionic components to work properly */import'@ionic/vue/css/core.css';/* Basic CSS for apps built with Ionic */import'@ionic/vue/css/normalize.css';import'@ionic/vue/css/structure.css';import'@ionic/vue/css/typography.css';/* Optional CSS utils that can be commented out */import'@ionic/vue/css/padding.css';import'@ionic/vue/css/float-elements.css';import'@ionic/vue/css/text-alignment.css';import'@ionic/vue/css/text-transformation.css';import'@ionic/vue/css/flex-utils.css';import'@ionic/vue/css/display.css';/* Theme variables */import'../src/theme/variables.css';
We need to do some additional setup to get our stories wrapped with IonApp and ensure we get the IonicVue injected into the app.
What is going on below is that we are importing the ionic components we need, IonApp and IonVue and then utilizing the app object we get from storybook along with the decorator; we are creating a container to render the story that has IonicVue injected and wraps the story with IonicApp.
We could have done this at the story level, but since we know that all of our stories will need to be wrapped; I did it at the top level of the project
Part of the magic of the story is getting events from the component emitted so you can verify the component is working as expected.
In this component we need to know when the user has clicked the login button or the create account button. We also need the contents of the form fields passed along with the event.
Our LoginForm will emit two events login and createAccount ; in order to get the events converted to actions that we can see inside of storybook, we can use "Action argType annotation"; which basically turns the argument into an action that can be displayed in storybook console
// import the component for use in storyimportLoginFormfrom"../LoginForm.vue";// set up the story containerexportdefault{title:"Example/LoginForm",component:LoginForm,argTypes:{onLogin:{action:"onLogin"},onCreateAccount:{action:"onCreateAccount"},},};// create the base templateconstTemplate=(args)=>({components:{LoginForm},setup(){return{args};},// Then, those values can be accessed directly in the templatetemplate:"<div class='ion-padding'><login-form v-bind='{...args}'/></div>",});exportconstBasic=Template.bind({})
final code for LoginForm.vue
<template><div><h2>
LOGIN FORM
</h2><p><ion-item><ion-inputtype="text"v-model="credentials.email"/></ion-item><ion-item><ion-inputtype="password"v-model="credentials.password"autocomplete="new-password"/></ion-item><ion-button@click="handleLogin">LOGIN</ion-button><ion-button@click="handleCreateAccount">CREATE ACCOUNT</ion-button></p></div></template><scriptlang="ts">
import {IonButton,IonInput,IonItem} from "@ionic/vue";
import {defineComponent,ref} from "vue";
export default defineComponent({name:"LoginForm",emits:["login","createAccount"],setup(props,{emit}){constcredentials=ref<any>({email:"",password:""});return{credentials,handleLogin:()=>emit("login",{...credentials.value}),handleCreateAccount:()=>emit("createAccount",{...credentials.value})};},components:{IonButton,IonInput,IonItem}});
</script><stylelang="scss"scoped></style>
This is the final code for the Home.vue component that the LoginForm is contained in
<template><ion-page><ion-header:translucent="true"><ion-toolbar><ion-title>Blank</ion-title></ion-toolbar></ion-header><ion-content:fullscreen="true"class="ion-padding"><login-form@createAccount="doCreateAccount"@login="doLogin"/></ion-content></ion-page></template><scriptlang="ts">
import {IonContent,IonHeader,IonPage,IonTitle,IonToolbar} from "@ionic/vue";
import {defineComponent} from "vue";
import LoginForm from "./LoginForm.vue";
export default defineComponent({name:"Home",components:{IonContent,IonHeader,IonPage,IonTitle,IonToolbar,LoginForm},setup(){return{doLogin:(params:any)=>{console.log("doLogin",params);},doCreateAccount:(params:any)=>{console.log("doCreateAccount",params);}};}});
</script><stylescoped></style>