Tailwind VariantsのSlotsがMonorepoと相性抜群だった

:::note info
この記事はEDOCODE [Advent Calendar 2024](https://adventar.org/calendars/10618)、12月24日(火)の記事です。

1つ前の記事は、エンジニアのSaloniさんによる[Building Smart, Not Perfect: Avoiding Over-Engineering in MVP
](https://medium.com/@saloni.ag14/building-smart-not-perfect-avoiding-over-engineering-in-mvp-21606fe02a2b)でした。

また、グループ会社の [Wano Group Advent Calendar 2024](https://qiita.com/advent-calendar/2024/wano-group) もありますので、よろしければそちらもどうぞ！
:::

# はじめに
EDOCODEエンジニアのNakoです。弊社では現在フロントエンド開発環境を Remix(React Router v7) + Tailwind へリプレイスする作業を進めています。また複数のプロジェクトを管理できるように Monorepo(モノレポ)の構成を採用しています。

今回は Tailwind Variants の slots 機能を使って、Monorepo 環境でのスタイリングを改善した方法をご紹介します。とても整理されたコードになり開発効率が向上したと思います。

## Monorepo とは

Monorepo(モノレポ)とは 1 つのリポジトリに複数のプロジェクトをまとめて管理する方法です。これにより、プロジェクト間の依存関係を明確にし、コードの再利用や共有が容易になります。
下記のように共通の UI コンポーネントライブラリを一箇所で管理し、複数のプロジェクトで使い回することができます。

![Frame 6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957453/95ab775d-615f-36d1-af74-49b93b5ad8d8.png)

# 親要素から子要素へのスタイル適用

再利用性を高めるため、コンポーネントには最小限のスタイル、もしくはスタイルを適用していない状態で作成します。しかし、これらのコンポーネントは通常、複数の要素で構成されています。

例えば、こんな感じです

```jsx
const ChildComponent = () => {
    return (
        <section>
            <h1>Title</h1>
            <div>
                <p>
                    Lorem ipsum dolor sit amet, consectetur adipisci elit, sed
                    eiusmod tempor incidunt ut labore et dolore
                </p>
                <div>
                    <span>Notes</span>
                    <div>Ut enim ad minim veniam</div>
                </div>
            </div>
        </section>
    );
};
```
このような場合、親コンポーネントでスタイルオブジェクトを定義し、それを子コンポーネントに props として渡すのが一般的かと思います。この作業が冗長だしわかりにくいなあと感じていました。もっと親コンポーネントから柔軟にスタイルを制御したいです。

# Tailwind Variants slots
https://www.tailwind-variants.org/docs/slots

ここで、Tailwind Variants の slots の出番です。この機能を使うと、非常にわかりやすくて直感的にスタイルを適用できます。
まず、親コンポーネントでスタイルを定義します。

```jsx
import { tv } from "tailwind-variants";
const ParentComponent = () => {
    const ChildStyle = tv({
        slots: {
            base: "p-4 bg-slate-300 rounded-xl text-gray-700",
            title: "text-lg  mx-auto font-bold",
            body: "pt-6 text-left",
            text: "text-md font-medium",
            info: "mt-4 p-4 bg-slate-100 rounded-xl",
            label: "block text-sm text-sky-500",
            name: "text-md",
        },
    });
    return <ChildComponent className={ChildStyle()} />;
};
```

そして、子コンポーネントで各要素のスタイルを適用します。

```jsx
const ChildComponent = ({ className }) => {
    const { base, title, body, text, info, label, name } = className;
    return (
        <section className={base()}>
            <h1 className={title()}>Title</h1>
            <div className={body()}>
                <p className={text()}>
                    Lorem ipsum dolor sit amet, consectetur adipisci elit, sed
                    eiusmod tempor incidunt ut labore et dolore
                </p>
                <div className={info()}>
                    <span className={label()}>Notes</span>
                    <div className={name()}>Ut enim ad minim veniam</div>
                </div>
            </div>
        </section>
    );
};
```
コードの可読性が大幅に向上し、スタイルの管理が容易になりました。

# compoundSlots

さらに`compoundSlots`を使うと複数のスロットに同時にクラスを適用でき、コードの重複を減らすことができます。
下記の例では、base と info スロットの両方に `p-4 rounded-xl` クラスを適用しています。これにより、共通のスタイルをより簡潔に記述できます。

```javascript
import { tv } from "tailwind-variants";

const style = tv({
    slots: {
        base: "p-4 bg-slate-300 rounded-xl text-gray-700",
        title: "text-lg  mx-auto  font-bold",
        body: "pt-6 text-left",
        text: "text-md font-medium",
        info: "mt-4 p-4 bg-slate-100 rounded-xl",
        label: "block text-sm text-sky-500",
        name: "text-md",
    },
    compoundSlots: [
        {
            slots: ["base", "info"],
            class: ["p-4 rounded-xl"],
        },
    ],
});
```

# まとめ

Monorepo 環境での大規模プロジェクトにおいて、Tailwind Variants の slots は非常に強力な機能でスタイル管理は劇的に改善されると思います。
Tailwind Variants の slots 機能を使うことで、コードの可読性や再利用性の向上など様々なメリットが得られて新しい可能性が開けた気がします！

---
明日、12/25(水)の記事は、kyoさんによる「Everyone's Christmas Wishes at EDOCODE」という内容の予定です。


私たちWanoグループでは人材募集をしています。興味のある方は、下記のリンクからぜひ募集中の求人をご確認ください！
[JOBS | Wano Group](https://group.wano.co.jp/jobs/)