Storybook for Vue

Build UI components isolated from the business logic and context of your app
21.04.2020
Kailaash Balachandran
Tags

We live in the “component-based” era, which essentially means building design components that are modular and can be integrated to create a unified layout, just like LEGOS. While working with such component centric designs, it is hard to predict every possible state of the component. Visual tests for edge cases are skipped, resulting in us paying for it later while debugging. This is when Storybook comes in handy. It not only enumerates all possible states of your components, but also allows the development of UI components in isolation without having to worry about the dependencies and requirements of the app.

Why use Storybook?

The components are typically divided into two types depending on their characteristics: presentational (or dumb) and container components. Presentational components are mostly concerned with generating some markup to be outputted. They don’t manage any state, except for states related to the presentation. Container components are primarily concerned with the “backend” operations, such as fetching data from the API, etc.

With Storybook integrated into the app, it enforces the separation of components into presentational and container types. Upon importing dumb components in Storybook, we can visualize every conceivable state and focus on one state at a time as we develop the component. Developing components in separation can help you gain control of your project workflow, which allows you to build and test components without having to worry about the whole project logic. By promoting such componentization and modularisation, the habit of building reusable dumb components is fostered. Thereby reducing complicated unit tests and hard-to-reproduce states. Also, the time is invested upfront into figuring out the components’ architecture, which improves productivity in the long term.

The most imperative aspect of Storybook is the support for many addons that come with flexible APIs to customize the workshop as you desire. In particular, the latest addon on generating docs for UI components and libraries, called the Storybook Docs, deserves special mention as it gets you auto-generated component documentation. It also adheres to best practices from community members such as Auth0, Airbnb, and Microsoft. If you require component documentation and stories in one file, you could use the MDX addon. It lets you write JSX in Markdown thus aiding support for long-form documentation.

Speaking of presenting the component stories, Storybook can be easily exported as a static app to be deployed to any host. This makes it a lot easier for designers to see how their designs come to life, interact, and review the different states of the components.

Using Storybook with Vue

Vue is one of the most fast-growing JavaScript frameworks today. Since its advent in 2013, the popularity has grown steadily in recent months and years. If you’re starting an all new Vue project and would like to set up Storybook, this tutorial is apt for you as this post iteratively describes the steps from bootstrapping a Vue application using the Vue CLI to writing stories in Storybook. Though I’m bootstrapping a new Vue application in the next step, my points are not restricted only to new projects but could be applied for integrating Storybook with existing projects as well. I intend to use the components generated by @vue-cli to better demonstrate Storybook integration and interactively test user interface components.

To get started, let’s bootstrap a Vue application using the Vue CLI.

Bootstrap Vue JS project from @vue/cli

To install @vue-cli globally, run

npm install -g @vue/cli@latest

Note that if you have trouble upgrading to the latest CLI (version 4 & above), we suggest you first remove the older version of Vue CLI before installing the latest. To do so;

# Uninstall
npm uninstall -g vue-cli
# Install the latest version
npm install -g @vue/cli@latest

and then you can issue the below command to create a new project

# Create a project
vue create storybook-project

From the menu, select the default preset, which scaffolds an all-new Vue application with zero manual configuration. With the storybook-project as your current working directory, run npm run serve to start the application on port 8080.

Install Storybook for Vue

Now that we have our Vue application up and working, we can install Storybook by running the following command.

npm i --save-dev @storybook/vue

Finally, in the scripts section in your package.json, add the following npm script that lets you start and run Storybook easily.

{
 "scripts": {
   "storybook": "start-storybook -p 8081"
 }
}

The optional -p argument designates the port where Storybook will run: in this case 8081. Additionally, Storybook expects the babel-preset-vue peer dependency to be added in the project, to do so, run:

npm i --save-dev babel-preset-vue

Configuring Storybook

To configure Storybook, create a directory called .storybook in the project root, and within it, create a config.js file with the following content to hold all configurations custom to the project. The details given in the file tell Storybook where to find the stories, presets, and the addons required to build the Storybook UI.

import { configure } from '@storybook/vue';
configure(require.context('../src', true, /\.stories\.js$/), module);

The configure() method looks for all the stories underneath your …/src directory that match the pattern *.stories.js. It is recommended to co-locate the stories along with the individual component files, but as with everything, there is no strict way of doing this, so you can place them wherever you choose.

Writing the first Story

Since the Vue application is bootstrapped raw using the @vue/cli, we have the primary HelloWorld.vue component present in the /src/components folder. Now that we have the basic Storybook setup also ready, it’s time to write our first Story for HelloWorld.vue. To do so, create a HelloWorld.stories.js file just beside the HelloWorld.vue component and add the following code.

import HelloWorld from './HelloWorld.vue';
import { storiesOf } from '@storybook/vue';

const stories = storiesOf('HelloWorld', module)

stories.add('with hello message', () => ({
 components: { HelloWorld },
 props: { 
  msg: {
   default: "Hello"
  }
 },
 template: '<HelloWorld :msg="msg"/>'
}));

The code above imports storiesOf from ‘@storybook/vue’, and by declaring the add method with the component (HelloWorld, in this example), we tell Storybook that we want stories of the HelloWorld component. In a nutshell, the storiesOf() declares the section title, and the add() method acts in a manner similar to adding a chapter in a story book. Within the add method, we define the component being staged with props as defined in HelloWorld.vue.

What we have here is a predefined story with default props, but I did mention Storybook also allows us to interact with the interface, right? Let’s see how to add interactivity to stories with the Knobs decorator, which adds interactivity to the component based on their props. To add Knobs addon to our project, run;

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

Then create an addons.js file within the .storybook directory and register the addon as mentioned below

import '@storybook/addon-knobs/register';

Now, let’s add the Knobs decorator to our HelloWorld.stories.js by importing the text knob to interact with the msg prop.

import HelloWorld from './HelloWorld.vue';
import { storiesOf } from '@storybook/vue';
import { withKnobs, text } from '@storybook/addon-knobs';

const stories = storiesOf('HelloWorld', module)

// Add the `withKnobs` decorator to add knobs support to your stories.
stories.addDecorator(withKnobs);

stories.add('with hello message', () => ({
 components: { HelloWorld },
 props: { 
  msg: {
   /* 
   * The text(label, defaultValue) method from Knobs allows you to receive 
   * value dynamically in the Storybook Ui.
   */
   default: text('Text', 'Hello Storybook')
  }
 },
 template: '<HelloWorld :msg="msg"/>'
}));

Now when you restart Storybook again, you’ll notice a new addon area with the knobs tab as seen below. The input field with the label Text adds reactivity to the msg prop, so the component is re-rendered whenever the input text is modified. This comes in handy to test props in components, the msg prop in the example, and lets us develop components interactively.

Storybook for vue blog post- Hello Storybook image

Running Storybook

We now have the foundation of our first Story, Let’s check if Storybook runs and renders the Story as expected. Within the root directory, run

npm run storybook   

And, once the build succeeds, open localhost:8081 in the browser to see your first Story in all its glory. What’s remarkable to note is that we don’t have to run the Vue application in parallel while using Storybook as it compiles the component and renders them in isolation.

Storybook provides a great developer experience while building the UI, but is not just limited to devs. It comes with a handy tool that exports Storybook into a static app, which can be deployed in any static hosting servers. To do so, add the following to the npm scripts in package.json.

"build-storybook": "build-storybook -c .storybook -o .out"

Here, the -c command argument tells Storybook where to find the configuration files and the -o argument specifies the output directory to which the built static application is placed. To deploy, you can copy the contents of the .out directory directly into GitHub pages with the storybook-deployer tool or to any hosting service.

Summary

To recap, we’ve now learned how to integrate Storybook to an all new Vue application and add basic interactions using the Knobs decorator. If you wish to integrate Storybook in existing projects, the integration steps remain the same as discussed. If the project has complex components, first break them into presentational, and container types, and then further segregate them in the most uncomplicated way. In practice, components can be conceived from the bottom to the top: For instance, start with the small presentation components, adjust their style and content, then move to the more significant components that rely on component composition to present them. Storybook helps you to concentrate on treating each part as a truly modular UI puzzle piece. Additionally, to benefit larger teams, Storybook inspires developing reusable components which can be used not only within a project, but also throughout an organization that requires a standardized look and feel for successful branding.


Image Source: Unsplash