Add Storybook to Vue3 project

This is a continuation of this article: https://crocodayo.hashnode.dev/one-way-to-bootstrap-vue3-project
Install Storybook
Simply follow the instruction in this page: https://storybook.js.org/docs/get-started/install
Make sure to select Vue
to get the right example.
$ npm create storybook@latest
And follow the prompt:
Need to install the following packages:
create-storybook@9.1.0
Ok to proceed? (y)
...
✔ New to Storybook? › No: Skip onboarding & don't ask again
✔ What configuration should we install? › Minimal: Component dev only
...
Running Storybook
> vite-4@0.0.0 storybook
> storybook dev -p 6006 --quiet
storybook v9.1.0
Once done, Storybook will automatically open the default browser and open page http://localhost:6006
The setup will create a few configuration files (/.storybook/main.ts
and /.storybook/preview.ts
) and an example directory (/src/stories
)
The examples will be loaded (NOTE: the examples in /src/stories
directory can be safely deleted)
Add stories for our Rando component
First, add a new file called Rando.stories.ts
and place it in the same directory as Rando.vue
Copy an example content from this page: https://storybook.js.org/docs/writing-stories/typescript
Update the component name and the content should look like this:
import type { Meta, StoryObj } from '@storybook/vue3-vite'
import Rando from './Rando.vue'
const meta = {
component: Rando,
} satisfies Meta<typeof Rando>
export default meta
type Story = StoryObj<typeof meta>
export const Primary = {
args: {
msg: 'Some message',
},
} satisfies Story
The above code will create a story for Rando component called Primary
and we simply pass an example prop (i.e. Some Message
).
Improve Rando with Vuetify
Let’s improve Rando to use Vuetify. We will use v-label
, v-textfield
and v-button
. And when the button clicked, it will emit a save
event that include the value of the textfield to the parent.
<script setup lang="ts">
import { ref } from 'vue'
const yourName = ref('')
defineProps<{ msg: string }>()
const emit = defineEmits<{
(e: 'save', name: string): void
}>()
function onSave () {
emit('save', yourName.value)
}
</script>
<template>
<v-container>
<v-label>Message: {{ msg }}</v-label>
<v-form>
<v-text-field
v-model="yourName"
label="Your Name"
/>
<v-btn @click="onSave">Save</v-btn>
</v-form>
</v-container>
</template>
The improved Rando component should display a label, a textfield, and a button
But Storybook does not display it nicely.
This is because Storybook has no access to Vuetify. To fix this, update the /.storybook/preview.ts
file.
This is how the file before:
import type { Preview } from '@storybook/vue3-vite'
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
}
export default preview
And after:
import type { Preview } from '@storybook/vue3-vite'
import { setup } from '@storybook/vue3-vite'
import { vuetify } from '../src/plugins/vuetify'
setup(app => {
app.use(vuetify)
})
const preview: Preview = {
... no changes ...
// /src/plugins/vuetify.ts
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import { mdi } from 'vuetify/iconsets/mdi-svg'
import 'vuetify/styles/main.css'
export const vuetify = createVuetify({
components,
directives,
icons: {
defaultSet: 'mdi',
sets: { mdi },
},
})
Refresh the Storybook and it should look like this now:
Update Rando.stories.ts
to capture the event
...
import { fn } from 'storybook/test' // <= add this
...
export const Primary = {
args: {
msg: 'Hello Primary',
onSave: fn(), // <= and add this
},
} satisfies Story
Type some text in Your Name
textfield and click Save
button.
:-) That’s All
Subscribe to my newsletter
Read articles from EJ directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
