目次
はじめに
概要
Next.js+Tailwind CSS+Storybookを使って、コンポーネントベースのフロントエンド開発に挑戦しました。
下記の順番で進めていきます。
- 環境構築
- Storybookで管理しながらコンポーネントを作成
- APIの呼び出し
- コンポーネントを組み合わせてレイアウト構築
完成図
宝くじ抽選アプリを作っていきます。

開発環境
私はWSL2で作業しました。
node.jsとnpmのバージョンは以下のとおりです。
$ node -v
v23.2.0
$ npm -v
10.9.0
環境構築
Next.js+TypeScript+Tailwind CSSの用意
Next.jsアプリを作る
・アプリを作りたい場所で下記を実行
・今回はTypeScriptを使いたいので--tsを指定
$ npx create-next-app@latest my-next-app --ts
・コンソールで下記を質問されるのでそれぞれ選択+Enter
・2番目の「Tailwind CSS?」は必ずYes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like your code inside a `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to use Turbopack for next dev? … No
✔ Would you like to customize the import alias (@/* by default)? … No
・追加で質問される場合もYesを選択
Need to install the following packages:
create-next-app@15.0.3
Ok to proceed? (y) y
・pacakgeのインストールなど辛抱強く待ちます…
Next.jsアプリを起動、動作確認
・完了後、プロジェクト名のフォルダへ移動(package.jsonがあるところ)
・下記を実行して起動
$ npm run dev
・http://localhost:3000 へアクセス
・page.tsxを適当に修正し、リアルタイム更新されることを確認
・今回は下記のようにTailwind CSSのクラス名を追加してみました
<li className="text-red-500">Save and see your changes instantly.</li>
・変更が反映されたのでNext.jsとTailwind CSSの用意完了!

リアルタイム更新されないとき
・package.jsonにあるscriptのdevに「WATCHPACK_POLLING=true」を追記
・Next.jsのファイル変更を検知が、WSL2では期待通りに動作しないことがあるようです
・ポーリング方式(一定間隔でファイル変更をチェックする)にすることで、確実に変更検知するようになりました
"dev": "WATCHPACK_POLLING=true next dev",
Storybookの用意
Storybookをインストール
・package.jsonがある場所に移動
・Storybookをインストール
$ npx storybook init
・下記のように質問されたらYes
Need to install the following packages:
storybook@8.5.1
Ok to proceed? (y)
・こちらもmpacakgeのインストールなど辛抱強く待つ…
Storybookを起動、動作確認
・初回は自動起動しました
・次回以降は下記で起動させればOK
$ yarn storybook
・UIを適当に操作してみます
・Buttonコンポーネントが用意してありました

・Storybookの用意完了!
リアルタイム更新されないとき
・package.jsonにあるscriptのstorybookに「WATCHPACK_POLLING=true」を追記
"storybook": "WATCHPACK_POLLING=true storybook dev -p 6006"
フォルダ構成を整える
CSS置き場
・Next.jsアプリを作成すると、デフォルトで/src/app/globals.cssが生成されます
・今回は/src/cssを用意し、ここにglobals.cssを置くことにします
image置き場
・Next.jsアプリを作成すると、デフォルトで/publicに画像が直接置かれています
・今回は/public/imagesを作成し、ここに画像を置くことにします
・フォントを置く場合も、/public/fonts を用意すれば良さそうです
コンポーネント置き場
・Storybookをインストールすると、デフォルトで/src/storiesにサンプルのコンポーネントが生成されます
・今回は /src/componentsを用意し、ここに作成したコンポーネントを置くことにします
・コンポーネントごとに更にフォルダを作成し、.tsxと.stories.tsxを配置します
ページの用意
Next.jsだとApp Routerを使う場合が多いので、宝くじ抽選画面として/src/app/lotteryを作成しました。
上記を踏まえて、以下の構成になりました。
my-next-app
├── public
| └── images
| └── logo.svg
├── src
| ├── app
| | ├── lottery
| | | └── page.tsx
| | ├── layout.tsx
| | └── page.tsx
| ├── css
| | └── global.css
| └── components
| └── button
| ├── button.css (これは後で消す)
| ├── Button.tsx
| └── Button.stories.tsx
└── package.json
StorybookにTailwind CSSを適用させる
適用確認のための準備
・サンプルのButtonコンポーネントを↑のように配置しておきます
・その他のサンプルはすべて削除します
・ボタンラベル部分を<span>で囲み、Tailwind CSSのクラス名を記載
<span className='text-red-500'>{label}</span>
・/src/app/lottery/page.tsxを作成し、宝くじ抽選画面を用意
・先ほど用意したButtonコンポーネントを呼び出します
"use client";
import { Button } from "../../comopnents/button/Button";
export default function Home() {
return (
<div className="p-5">
<Button primary={false} label="宝くじ抽選ページで呼び出した" />
</div>
);
}
適用確認
・npm run devでアプリを起動
・http://localhost:3000/lotteryへアクセスすると、Buttonコンポーネントのラベルが赤色になっていました↓

しかし、Storybookでは赤色になっていません…!↓

適用させる
global.cssの先頭に「Tailwindを使う」宣言があるので、Storybook側でもこれを読み込む必要があるようです。
@tailwind base;
@tailwind components;
@tailwind utilities;
・/.storybook/preview.tsに下記を追記
import "../src/css/globals.css";
・Tailwindsに適用範囲を追加(今回のようにsrc/componentsにコンポーネントを作成する場合は不要)
import type { Config } from "tailwindcss";
export default {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
・Storybookを起動しなおして確認すると、アプリ側と同じく赤色になっている=Tailwind CSSが適用されました!

Tailwind CSSが反映されない場合
・/postcss.config.mjsを/postcss.config.jsに変更、中身を下記に変更
module.exports = {
plugins: {
tailwindcss: {},
},
};
おわりに
環境構築は以上です。
次回はコンポーネントを作っていきます。
