実践的な Tailwind CSS: ゲートキーパー・アーキテクチャ

大規模な組織では、誰もがすべてのページにスタイルを適用できるわけではありません。コードをクリーンに保つために、特定の構造を採用しています。

Shopify Polaris のような成熟したデザインシステムでは、2つの異なる役割を使い分けています。

  • コンポーネント作成者 (ゲートキーパー): このチームはコアとなる UI を構築します。Tailwind クラスを記述し、アクセシビリティ、ダークモード、デザイントークンを管理します。

  • 機能開発者 (アセンブラー): このチームは製品やダッシュボードを構築します。ビジネスロジックとレイアウトに集中し、色や余白(spacing)を直接選択することはありません。

組織は、Lint ルールやコードレビューによってこの境界を厳格に維持します。

推奨されること: • flex、grid、gap などのレイアウトユーティリティを使用すること。

避けるべきこと: • feature ページ内に bg-indigo-600text-lg といった新しいビジュアルスタイルを直接追加すること。代わりに既存のコンポーネントを使用してください。

コードでの実装例は以下の通りです。

デザインシステムチームは、@/components/ui/button.tsx に再利用可能なボタンを作成します。ビジュアルスタイルをここに集約します。

import React from 'react';

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'primary' | 'secondary';
  className?: string;
}

export function Button({
  variant = 'primary',
  className = '',
  children,
  ...props
}: ButtonProps) {
  const baseStyles = "px-4 py-2 rounded-lg font-medium text-sm transition-all focus:outline-none focus:ring-2 focus:ring-offset-2";

  const variants = {
    primary: "bg-indigo-600 text-white hover:bg-indigo-700 focus:ring-indigo-500",
    secondary: "bg-slate-100 text-slate-700 hover:bg-slate-200 focus:ring-slate-500"
  };

  return (
    <button className={`${baseStyles} ${variants[variant]} ${className}`} {...props}>
      {children}
    </button>
  );
}

その後、機能開発者はこれらのブロックを組み合わせてページを構築します。

import { Button } from "@/components/ui/button";

export default function Dashboard() {
  return (
    <div>
      <Button variant="primary" className="mt-4">
        Save Changes
      </Button>
    </div>
  );
}

この構造には、主に3つのメリットがあります。

  1. メンテナンスの容易化: ボタンを削除しても、不要なCSSが残ることはありません。
  2. アップデートの迅速化: ブランドカラーが indigo から violet に変わった場合、1つのファイルを変更するだけで、アプリ全体にその変更が反映されます。
  3. 一貫性: すべての開発者が同じデザイントークンを使用できます。

目標は、単にTailwindに関することだけではありません。それは、システムを構築する側と、それを利用する側の間に境界線を設けることにあります。

パート2では、アーキテクチャを壊すことなく、デザインの例外をどのように扱うかについて解説します。

出典: https://dev.to/cathylai/real-world-tailwind-css-the-gatekeeper-architecture-a-senior-developers-guide-part-12-m36