コンポーネントファースト戦略
zudo-docがカスタムCSSクラス名ではなく、ユーティリティクラスを持つコンポーネントを使用する理由。
zudo-docはコンポーネントファースト戦略に従います:UIは常にTailwindユーティリティクラスを持つコンポーネントとして表現します。カスタムCSSクラス名を別のスタイルシートで作成することはしません。
問題
ユーティリティCSSフレームワークとコンポーネントフレームワークを併用するプロジェクトでは、開発者は従来のCSSパターンに戻りがちです。コンポーネント内でユーティリティクラスを組み合わせる代わりに、.profile-card、.btn-primary、.sidebar-navといったカスタムCSSクラス名を別のスタイルシートやCSSモジュールで作成します。
これにより、コードベースが断片化します:
- ユーティリティをインラインで使うコンポーネント
- カスタムCSSクラスを導入するコンポーネント
- 両方のアプローチを混在させるコンポーネント
ルール
コンポーネント自体が抽象化です。 .cardや.btn-primaryのようなCSSクラス名は不要です。コンポーネントがカプセル化を、ユーティリティクラスがスタイリングを担当します。
- カードが必要? → ユーティリティクラスを持つ
<Card>コンポーネントを作成 - ボタンバリアント? →
<Button variant="primary">コンポーネント - レイアウトパターン? →
<PageLayout>コンポーネント
zudo-docでの実践
zudo-docはAstroコンポーネント(.astro)とReactアイランド(.tsx)をTailwind CSS v4ユーティリティとともに使用します。
Astroコンポーネント
<!-- ユーティリティクラスをインラインで使用 -->
<footer class="border-t border-muted bg-surface px-hsp-xl py-vsp-xl">
<div class="text-center text-caption text-muted">
<Fragment set:html={copyright} />
</div>
</footer>
.footerクラスなし。footer.module.cssなし。コンポーネントが抽象化です。
アンチパターン
/* 間違い — カスタムCSSクラスを作成しない */
.profile-card { display: flex; gap: 1rem; }
<!-- 間違い — カスタムクラス名はデザインシステムをバイパスする -->
<div class="profile-card">...</div>
<!-- 正しい — ユーティリティクラス、コンポーネントが抽象化 -->
<div class="flex gap-hsp-md p-hsp-lg">...</div>
バリアントはPropsで
CSSモディファイアクラス(.btn--primary)ではなく、コンポーネントプロップスを使用:
function Button({ variant = "primary", children }) {
const styles = {
primary: "bg-accent text-bg hover:bg-accent-hover",
secondary: "bg-surface text-fg border border-muted",
};
return (
<button className={`${styles[variant]} font-semibold py-vsp-xs px-hsp-md rounded`}>
{children}
</button>
);
}
デザイントークンを使用
任意の値ではなく、プロジェクトトークンを常に使用:
<!-- 間違い — 任意の値はデザインシステムをバイパスする -->
<div class="p-[1.2rem] text-[0.875rem]">
<!-- 正しい — デザイントークンを使用 -->
<div class="p-hsp-md text-small text-muted">
利用可能なトークンについてはデザインシステムを参照してください。
カスタムCSSが許容される場合
zudo-docでカスタムCSSが許容される唯一の場所はsrc/styles/global.cssです:
- コンテンツタイポグラフィ —
.zd-contentクラスはMDXパイプラインが生成する要素をスタイリング - デザイントークン定義 — Tailwindトークンを登録する
@themeブロック
それ以外のすべて(すべてのコンポーネント、レイアウト、UI要素)はユーティリティクラスを直接使用します。
ルールのまとめ
- 常にコンポーネントを作成 — CSSクラスではなく
- ユーティリティクラスを直接使用 — コンポーネントマークアップ内で
- CSSモジュールファイルやカスタムクラス名を作成しない
- バリアントにはプロップスを使用 — CSSモディファイアではなく
- コンポーネントを組み合わせる — より多くのCSSではなく、小さなコンポーネントから複雑なUIを構築
- プロジェクトトークンを使用 —
text-fg、bg-surface、p-hsp-md、任意の値ではなく