Storybook駆動開発とは?UIコンポーネントを効率よく作る
こんにちは、デザイン戦略部の哲也です。
Storybook駆動開発を知っていますか?
ページ全体をいきなり作るのではなく、「ボタン」や「モーダル」、「入力欄」などのUI部品を先に個別に作るという開発スタイルがあります。
こうしたUIパーツをひとつずつ作って確認できるツールが、Storybook(ストーリーブック)です。
この記事では、Storybookとは何か、Storybook駆動開発の考え方やメリット・デメリットなどを紹介していきます。
Storybookとは?
Storybookとは、VueやReactなどのフレームワークで作ったUIコンポーネントを単体で開発・確認・ドキュメント化できる開発ツールです。
Storybookを使うと、ページ全体を表示しなくても、個々のボタンやフォームなどのパーツをブラウザ上で確認・切り替え・テストしながら開発することができます。
Storybook駆動開発とは?
Storybook駆動開発とは、ページ全体を作る前に、まずStorybook上でUIコンポーネントを設計・開発・テストする開発手法です。
ページ全体を先に作って、そこにUIをあてはめていくという従来のやり方とは違い、UIを先に作ってあとからページに組み込むという流れになります。
Storybook駆動開発のメリット
- UIの状態ごとにテストしやすい(propsの組み合わせも簡単に確認できる)
- デザイン・仕様共有がしやすい(Storybookがそのままドキュメントになる)
- ページの構造に依存しないので、UI開発がスムーズに進む
- 自動テストとの相性が良い
デメリット
- 実際に作られたAPIやstoreと乖離する可能性がある
- コンポーネントの状態をすべて再現するためのモックデータ(argsやダミー関数など)準備が必要になる
- Storybookの初期設定やstoriesの管理に少し手間がかかる
コード例
簡単なボタンコンポーネントとフォームの入力画面のコンポーネントを例として紹介します。
※VueやStorybookのバージョンによって記述方法が異なるのでご注意ください。
ボタン
MyButton.vue
<template>
<button :class="['btn', variant]" :type="type">
<slot />
</button>
</template>
<script setup>
defineProps({
variant: { type: String, default: 'primary' },
type: { type: String, default: 'button' }
});
</script>
<style scoped>
.btn {
padding: 0.5em 1em;
border: none;
cursor: pointer;
}
.primary {
background-color: #42b983;
color: white;
}
.secondary {
background-color: #eee;
color: #333;
}
</style>
MyButton.stories.js
import MyButton from './MyButton.vue';
export default {
title: 'Components/MyButton',
component: MyButton,
args: {
type: 'button',
variant: 'primary',
}
};
const Template = (args) => ({
components: { MyButton },
setup() {
return { args };
},
template: `
<MyButton v-bind="args">
{{ args.label }}
</MyButton>
`
});
export const Primary = Template.bind({});
Primary.args = {
label: 'Primary Button',
variant: 'primary'
};
export const Secondary = Template.bind({});
Secondary.args = {
label: 'Secondary Button',
variant: 'secondary'
};
export const SubmitButton = Template.bind({});
SubmitButton.args = {
label: 'Submit',
type: 'submit',
variant: 'primary'
};
プレビュー
Storybook上で以下のように確認できます。
各ボタンの見た目や表示内容を、実際に切り替えながら確認できます。
緑色の「Primary Button」表示
グレー背景の「Secondary Button」表示
Submitボタンの動作確認
入力画面
UserForm.vue
<template>
<form @submit.prevent="handleSubmit">
<div>
<label for="name" class="label">名前</label>
<input id="name" v-model="name" type="text" />
<p v-if="nameError" class="error">{{ nameError }}</p>
</div>
<div>
<label for="email" class="label">メールアドレス</label>
<input id="email" v-model="email" type="email" />
<p v-if="emailError" class="error">{{ emailError }}</p>
</div>
<MyButton type="submit" variant="primary" class="submit-button">
確認画面へ
</MyButton>
</form>
</template>
<script setup>
import { ref } from 'vue';
import MyButton from '../MyButton/MyButton.vue';
const props = defineProps({
defaultName: { type: String, default: '' },
defaultEmail: { type: String, default: '' },
onSubmit: { type: Function, default: () => {} },
});
const name = ref(props.defaultName);
const email = ref(props.defaultEmail);
const nameError = ref('');
const emailError = ref('');
const validate = () => {
nameError.value = '';
emailError.value = '';
let isValid = true;
if (!name.value.trim()) {
nameError.value = '名前を入力してください';
isValid = false;
}
if (!email.value.trim()) {
emailError.value = 'メールアドレスを入力してください';
isValid = false;
}
return isValid;
};
const handleSubmit = () => {
if (validate()) {
props.onSubmit({
name: name.value,
email: email.value
});
}
};
</script>
<style scoped>
.label {
margin-top: 10px;
display: block;
}
.error {
margin-top: 5px;
color: red;
}
.submit-button {
margin-top: 20px;
}
</style>
UserForm.stories.js
import UserForm from './UserForm.vue';
import { action } from '@storybook/addon-actions';
export default {
title: 'Components/UserForm',
component: UserForm,
};
const Template = (args) => ({
components: { UserForm },
setup() {
return { args };
},
template: '<UserForm v-bind="args" />',
});
export const Default = Template.bind({});
Default.args = {
defaultName: '',
defaultEmail: '',
onSubmit: action('フォームデータ'),
};
export const BackToInput = Template.bind({});
BackToInput.args = {
defaultName: '山田太郎',
defaultEmail: 'taro@example.com',
onSubmit: action('フォームデータ'),
};
プレビュー
Storybook上で以下のように確認できます。
入力画面の表示や動作を確認することができます。
初期表示
エラー表示
「確認画面へ」を押した時のデータを確認
確認画面から戻った時の表示
まとめ
今回はボタンと入力画面を例に紹介しました。
実際の業務では、入力 → 確認 → 完了 の3ステップのフォームにStorybookを活用して試してみました。
ボタンなどの細かいパーツを先に作成してStorybookで確認し、
その後「入力画面 → 確認画面 → 完了画面」の順で、各画面をStorybookで動作確認しながら開発を進めました。
動作確認や、propsの違いによる表示のチェックが簡単にできて、とてもスムーズに開発を進められると感じました。
Storybook駆動開発、ぜひ一度試してみてください!
ラクーンホールディングスではエンジニア・デザイナーを大募集中です!
少しでも興味がありましたらぜひご応募ください!