React×Tailwindで共通コンポーネントを作成

## 1. 背景
フロントエンド開発において、Tailwindは非常にスピード感を持って記述できる非常に便利はCSSフレームワークです。
しかしながら、Tailwindで開発をすることで、コンポーネントごとのUIの統一感がなくなってしまい全体としてチグハグになってしまうことが多いです。
そこで今回はTailwindの恩恵を受けつつも、統一感のあるWebサイトを作成する方法を紹介したいと思います。

## 2. 本記事の内容
- 共通コンポーネントをTailwindを用いて実装
    - 例としてボタンを作成
- 共通コンポーネントを組み合わせてUI部分を構築する


### 使用技術

- 言語
    - **TypeScript**
- フレームワーク(ライブラリ)
    - **React(Next.js)**
- CSSフレームワーク
    - **Tailwindcss**

[![My Skills](https://skillicons.dev/icons?i=typescript,react,tailwind)](https://skillicons.dev)

## 目次

- [1. 背景](#1-背景)
- [2. 本記事の内容](#2-本記事の内容)
- [3. 実装](#3-実装)
- [4. さいごに](#4-さいごに) 


## 3. 実装

ディレクトリ構成(本記事はNext.jsで実装しています)

```text
├── frontend/
     ├── src/
         ├── components/                    
         |    ├── common/                #共通コンポーネント
         |         ├── button.tsx        # ボタンコンポーネント
         ├── app/
              ├── home/
                   └── page.tsx          # ホームページ
```


#### 共通コンポーネントとしてボタンを作成します
- ボタンのパラメータ
    - 色
    - 大きさ
    - ボタンの文字
    - 押したときの挙動

```button.tsx
const ColorStyle = {
  red: "bg-red-500 text-white",
  blue: "bg-blue-500 text-white",
  green: "bg-green-500 text-white",
};
const sizeStyle = {
  small: "text-sm p-2 rounded-md",
  medium: "text-base p-4 rounded-md",
  large: "text-xl px-10 py-4 rounded-lg",
};

type Color = keyof typeof ColorStyle;
type Size = keyof typeof sizeStyle;

type ButtonProps = {
  color: Color;
  size: Size;
  text: string;
  onClick?: () => void;
};

const Button = ({ color, size, text, onClick }: ButtonProps) => {
  return (
    <button
      className={`${ColorStyle[color]} ${sizeStyle[size]} font-semibold`}
      onClick={onClick}
    >
      {text}
    </button>
  );
};

export default Button;

```


#### ページ作成

ここでは、ボタンを3つ呼び出します

```page.tsx![スクリーンショット 2024-12-03 17.31.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767231/8c4d5a2d-a144-cf60-6cf6-eb3332f77169.png)

"use client";

import Button from "@/components/common/button";

const Home = () => {
  return (
    <div className="flex flex-col items-center justify-center gap-12">
      <div className="flex flex-row gap-12">
        <Button color="blue" size="small" text="Small"></Button>
        <Button color="red" size="medium" text="Medium"></Button>
        <Button color="green" size="large" text="Large"></Button>
      </div>
    </div>
  );
};

export default Home;

```


#### ホームページの見た目

![スクリーンショット 2024-12-03 17.04.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767231/7794c2ba-3dbb-51ae-115a-d47e12397e16.png)

色やサイズ、文字などを設定することが出来ます。

## 共通コンポーネントを作成するポイント


tailwindはタイポしてもエラーにならず無視されるため、バグの温床になります。(←prettierなどで設定すれば別ですが)

これを解決するためにStyleを定義して、型はStyleを基に定義します。

### Ⅰ. Styleの定義
```tsx
const colorStyle = { //色指定
  red: "bg-red-500 text-white",
  blue: "bg-blue-500 text-white",
  green: "bg-green-500 text-white",
};
const sizeStyle = { //サイズ指定
  small: "text-sm p-2 rounded-md",
  medium: "text-base p-4 rounded-md",
  large: "text-xl px-10 py-4 rounded-lg",
};
```

### Ⅱ. Ⅰで定義したStyleを用いて型の定義
keyof typeof を用いるとStyleのkeyを型として持つことが出来ます
```tsx
type Color = keyof typeof colorStyle;
type Size = keyof typeof sizeStyle;
```

### Ⅲ. 共通コンポーネントの作成
```tsx
const Button = ({ color, size, text, onClick }: ButtonProps) => {
  return (
    <button
      className={`${colorStyle[color]} ${sizeStyle[size]} font-semibold`}
      onClick={onClick}
    >
      {text}
    </button>
  );
};
```

### Ⅳ. 共通コンポーネントの呼び出し
```tsx
import Button from "@/components/common/button";

const Home = () => {
  return (
    <div className="flex flex-col items-center justify-center gap-12">
      <div className="flex flex-row gap-12">
        <Button color="blue" size="small" text="Small"></Button>
        <Button color="red" size="medium" text="Medium"></Button>
        <Button color="green" size="large" text="Large"></Button>
      </div>
    </div>
  );
};

export default Home;
```


これらを用いて共通コンポーネントを作成します。
これによって、呼び出し先では指定した型以外を受け付けないためtypeScriptのエラーを出すことが出来ます。
また、エディタが型を認識するため補完機能を利用することが出来ます。

![スクリーンショット 2024-12-03 17.32.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767231/4baaf03b-c786-7f8b-3012-54492630d2c8.png)
(定義した型が候補に出てくるためタイポすることがなくなります。)



## 4. さいごに
いかがでしたでしょうか?
このように共通コンポーネントを作成することで、tailwindの恩恵を受けながら、安全に開発をすることが出来ます。
また、他のWebアプリ開発でも共通コンポーネントコンポーネントを使い回すことが出来るので非常に便利です。
tailwindとReactはフロントエンド開発において相性が最高なので是非使ってみてください!

この投稿が好評であれば、UIについての共通コンポーネントの作成方法も投稿したいと思います。