canvas-styling-conventions について
Drupal Canvas の React と Tailwind CSS 4 を使う開発者向けのスタイル規約スキルです。Canvas Headless と React の規則を区別し、テーマトークン、クラス結合、バリアントの使い方を示します。
主な機能
- 01Canvas Headless と React の判別
- 02Tailwind のテーマトークン利用
- 03cn() によるクラス結合
- 04CVA によるカラーのバリアント定義
- 05コンポーネントでの生のカラー値の回避
活用シーン
- 01Canvas コンポーネントのスタイル統一
- 02繰り返す色をテーマトークンに集約
- 03制限されたカラー設定の定義
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ drupal-canvas/ skills --skill canvas-styling-conventionsインストール後、Claude Code で/canvas-styling-conventionsを入力して読み込まれたか確認します。
詳細
プロジェクトの種類
このスキルを適用する前に、package.json を確認し、@drupal-canvas/headless または @drupal-canvas/headless- で始まる依存関係があるか確認してください。該当する依存関係がある場合、これは Canvas Headless コードベースです。まず canvas-headless を読んでください。以下の React 固有のガイダンスよりも、そちらが優先されます。このスキルの Tailwind 4 のテーマトークンに関するガイダンスは、ヘッドレスプロジェクトにもそのまま適用されます。一方、cn() と className のセクションは React 固有です。該当する依存関係がない場合、これは Canvas でレンダリングされる React コードベースです。コンポーネントは React(index.jsx/.tsx)で、このスキルの内容がすべてそのまま適用されます。プロジェクトの種類はこの2つのみです。
技術スタック
| 技術 | 用途 |
|---|---|
| Tailwind CSS 4.1+ | スタイリング |
| class-variance-authority(CVA) | コンポーネントのバリアント |
clsx + tailwind-merge(cn() 経由) | クラス名のマージ |
スタイリングにはこれらの依存関係のみを使用してください。サードパーティの CSS ライブラリを追加したり、新しいスタイリングユーティリティを作成したりしないでください。
Canvas Headless コードベースでは、drupal-canvas パッケージとその cn() はサポートされていません。CVA は、プロジェクトにインストールすれば、どのフレームワークでも使用できます。クラスのマージには、フレームワーク独自のクラス合成の慣用的な方法を使用してください。詳しくは canvas-headless を参照してください。
スタイリング規約
global.cssで定義されている Tailwind のテーマカラー(primary-*、gray-*)を使用してください。- 色の値をハードコードせず、テーマトークンを使用してください。
- 例にある既存のフォーカス、ホバー、アクティブ状態のパターンに従ってください。
cn() ユーティリティ
Tailwind クラスのマージには cn() を使用してください。条件付きクラスに clsx を使用し、tailwind-merge で競合するユーティリティを解決します。どちらかのソースからインポートできます。
import { cn } from '@/lib/utils';
// or
import { cn } from 'drupal-canvas';
使用例:
const Button = ({ variant, className, children }) => (
<button
className={cn(
'rounded px-4 py-2',
variant === 'primary' && 'bg-primary-600 text-white',
variant === 'secondary' && 'bg-gray-200 text-gray-800',
className,
)}
>
{children}
</button>
);
スタイルをカスタマイズできるよう className を受け付ける
このルールは React 固有です。Vue および Astro のコンポーネントでは、利用側がスタイルを上書きする必要がある場合、フレームワーク独自のクラスの受け渡し方法(Vue では属性のフォールスルー、Astro では class プロパティ)を使用してください。
すべての React コンポーネントは、スタイルを上書きできるよう className プロパティを受け付ける必要があります。利用側のクラスが優先されるよう、cn() の最後の引数として渡してください。
const Card = ({ colorScheme, className, children }) => (
<div className={cn(cardVariants({ colorScheme }), className)}>{children}</div>
);
className は実装/合成用のプロパティであり、エディター用のプロパティではありません。component.yml に className を追加したり、必須として指定したり、Canvas のメタデータに表示したりしないでください。
Tailwind 4 のテーマ変数
Canvas プロジェクトでは、Tailwind CSS 4 の @theme ディレクティブを使って global.css にデザイントークンを定義します。@theme { } 内で定義された変数は、Tailwind のユーティリティクラスとして自動的に利用可能になります。
利用可能なデザイントークンは、必ず global.css で確認してください。 色、フォント、ブレークポイント、その他のデザイントークンの信頼できる情報源は、@theme ブロックです。
テーマ変数とユーティリティクラスの対応
@theme で CSS 変数を定義すると、Tailwind 4 は変数の名前空間プレフィックスに基づいて、対応するユーティリティクラスを自動生成します。
@theme 内の CSS 変数 | 生成されるユーティリティクラス |
|---|---|
--color-primary-600: #xxx | bg-primary-600、text-primary-600、border-primary-600 |
--color-gray-100: #xxx | bg-gray-100、text-gray-100、border-gray-100 |
--font-sans: ... | font-sans |
--breakpoint-md: 48rem | レスポンシブ用プレフィックス md: |
パターンは次のとおりです。--{namespace}-{name} は {utility}-{name} になります。
例
global.css に次の定義があるとします。
@theme {
--color-primary-600: #1899cb;
--color-primary-700: #1487b4;
}
色を受け付けるユーティリティであれば、どれでもこれらの色を使用できます。
// Correct
<button className="bg-primary-600 hover:bg-primary-700 text-white">
Click me
</button>
// Wrong
<button className="bg-[#1899cb] text-white hover:bg-[#1487b4]">Click me</button>
任意の値(例:bg-[#xxx])は、テーマ変数を追加するほどではないまれな単発のケースであれば使用できます。ただし、色が複数箇所で使われる場合や、ブランド/デザインシステムの値を表す場合は、代わりに @theme に追加してください。
セマンティックエイリアス
テーマ変数は、ほかの変数を参照してセマンティックエイリアスを作成できます。
@theme {
--color-primary-700: #1487b4;
--color-primary-dark: var(--color-primary-700);
}
bg-primary-700 と bg-primary-dark のどちらも使用できます。意図をより明確に表せる場合(例:ブランドカラーの暗いバリエーションを表す primary-dark)は、セマンティックエイリアスを使用してください。
テーマ変数の追加または更新
デザインで、テーマにまだ定義されていない色、フォント、その他の値が必要な場合は、コンポーネントに値をハードコードせず、global.css の @theme ブロックに追加してください。
新しいテーマ変数を追加する場合:
- デザインに新しいブランドカラーまたは色合いが加わる
- 既存の値にセマンティックエイリアスが必要になる(例:
--color-accent) - デザインで特定のスペーシング、フォント、またはブレークポイントの値が繰り返し使われる
既存のテーマ変数を更新する場合:
- ブランドカラーが変わる(16 進数値を更新する)
- システム全体でデザイントークンを調整する必要がある
例 - 新しい色の追加:
@theme {
/* Existing tokens */
--color-primary-600: #1899cb;
/* New token for a success state */
--color-success: #22c55e;
--color-success-dark: #16a34a;
}
追加後すぐに、bg-success、text-success-dark などを使用できます。
テーマを整理された状態に保ちましょう。 関連するトークンは、その用途を説明するコメントとともにグループ化してください。global.css の既存の命名規則に従ってください(例:primary-100 から primary-900 のような番号付きの色合い、primary-dark のようなセマンティックな名前)。
色の props には色コードではなくバリアントを使用する
ユーザーが色コードを渡せる props は作成しないでください(16 進数値、RGB、HSL、生の色文字列など)。代わりに、CVA を使って、global.css のデザイントークンに対応する、人が理解しやすい少数のバリアントを定義してください。
利用可能なデザイントークンは必ず global.css で確認してください。 そこに定義されているトークン(primary-*、gray-* など)が、色の値の唯一の信頼できる情報源です。
誤り - 生の色値を許可する場合:
# Wrong
props:
properties:
backgroundColor:
title: Background Color
type: string
examples:
- '#3b82f6'
// Wrong
const Card = ({ backgroundColor }) => (
<div style={{ backgroundColor }}>{/* ... */}</div>
);
正しい例 - デザイントークンを使った CVA バリアント:
# Correct
props:
properties:
colorScheme:
title: Color Scheme
type: string
enum:
- default
- primary
- muted
- dark
meta:enum:
default: Default (White)
primary: Primary (Blue)
muted: Muted (Light Gray)
dark: Dark
examples:
- default
// Correct
import { cva } from 'class-variance-authority';
const cardVariants = cva('rounded-lg p-6', {
variants: {
colorScheme: {
default: 'bg-white text-black',
primary: 'bg-primary-600 text-white',
muted: 'bg-gray-100 text-gray-700',
dark: 'bg-gray-900 text-white',
},
},
defaultVariants: {
colorScheme: 'default',
},
});
const Card = ({ colorScheme, children }) => (
<div className={cardVariants({ colorScheme })}>{children}</div>
);
この方法により、次のことが実現できます。
- デザインシステム全体で色を統一できる
- ユーザーが任意の値ではなく、厳選された意味のある選択肢から選べる
global.cssのトークンを変更するだけで、テーマを簡単に更新できる- テスト済みの色の組み合わせによって、アクセシビリティが向上する