アプリ別テーマ
角丸・シャドウ・フォントをアプリごとにカスタマイズする公式手順
概要
色(--caroa-*)はCSS変数として最初から上書き可能でしたが、角丸・シャドウ・フォントはコンポーネントにrounded-md / shadow-sm / font-monoのようなTailwindクラスが直書きされており、--caroa-*を上書きしても反映されませんでした。
Tailwind CSS v4の@theme inlineを使ってPresetの変数間接化を導入しています。Tailwindがユーティリティ生成に使う--radius-* / --shadow-* / --font-*が、caroa独自の--caroa-radius-* / --caroa-shadow-* / --caroa-font-*を間接参照するようになっているため、アプリ側は--caroa-*を上書きするだけでrounded-* / shadow-* / font-*ユーティリティ全体の見た目を変更できます。
デフォルト値はTailwind v4の組み込みデフォルトと数値上一致させてあるため、何も上書きしないアプリの見た目は一切変化しません(非破壊)。
テーマの作り方
アプリ側でtheme.cssを1枚作り、:rootで--caroa-*を上書きします。
/* theme.css(アプリ側で新規作成) */
:root {
/* ブランドカラー
* hover / pressed も必ず併せて上書きします。上書きしないとcaroaデフォルト
* (オレンジ系)が残り、ホバーした瞬間にブランド色から離れてしまいます。
*/
--caroa-primary: 210 90% 50%;
--caroa-primary-hover: 210 90% 58%;
--caroa-primary-pressed: 210 90% 42%;
/* outline / ghost の状態色
* accent-action(hover)と accent-pressed(pressed)は必ずセットで上書きします。
* 片方だけ変えると、操作中に別の色系統へ切り替わってしまいます。
*/
--caroa-accent-action: 210 30% 92%;
--caroa-accent-pressed: 210 30% 84%;
--caroa-accent-foreground: 210 40% 20%;
/* 角丸: --caroa-radius だけ上書きすればsm/md/lgが連動して変わる */
--caroa-radius: 0.25rem;
/* フォント: next/fontで読み込んだCSS変数を渡す */
--caroa-font-sans: var(--font-geist-sans);
--caroa-font-mono: var(--font-geist-mono);
}/* globals.css */
@import "tailwindcss";
@import "@caroainc/ui-components/tokens";
@import "@caroainc/ui-components/animations";
@import "./theme.css"; /* tokensの後にimportする(後勝ちで上書きされる) */--caroa-radiusを上書きすると--caroa-radius-sm / -md / -lgがcalc()で連動して変わります(shadcn方式)。個別に段階を変えたい場合だけ--caroa-radius-sm等をピンポイントで上書きしてください。
--caroa-accent-actionはoutline / ghost系UIのhover背景、--caroa-accent-pressedはpressed背景です。アクセントの色系統をカスタマイズするときは、操作状態の連続性を保つため、この2変数をセットで上書きし、両surface上で十分なコントラストを持つ--caroa-accent-foregroundも同時に指定してください。ダークモードにも固有のアクセントを適用する場合は、.dark側でも同じ3変数をセットで上書きします。
ライブプレビュー
同じButton / Card / Badgeを、左は素のまま、右は--caroa-radiusをローカルに上書きして並べています(このページ内だけの局所上書き。CSS変数はDOMツリーを継承するため、上書きしたdivの内側にだけ効きます)。
このプレビューでは角丸を例にしていますが、同じ仕組みでシャドウとフォントも上書きできます。
シャドウ・フォントの上書き
このドキュメントサイトもTailwind CSS v4のCSS-first方式で構築され、tokens-variablesの@theme inlineを直接読み込んでいます。角丸・シャドウ・フォントはいずれも、対応する--caroa-*変数を上書きするとrounded-* / shadow-* / font-*ユーティリティへ反映されます。
/* theme.css(Tailwind v4アプリ側) */
:root {
--caroa-shadow-sm: 0 0 0 1px hsl(var(--caroa-border));
--caroa-font-mono: 'Courier New', monospace;
}<Card className="shadow-sm">...</Card>
<p className="font-mono">...</p>変数化されている範囲
| カテゴリ | 変数 | デフォルト値 | 上書きで効くクラス |
|---|---|---|---|
| 色(セマンティック) | --caroa-primary等--caroa-*全般 | カラーシステム参照 | bg-primary等の全セマンティックカラークラス |
| 状態色(hover / pressed) | --caroa-{primary,base,secondary,destructive,success,warning}-hover / -pressed、--caroa-accent-action / --caroa-accent-pressed | 原則はhoverを明るく・pressedを暗くする。白・黒の境界色やaccentなどの役割別例外は、正本design-system/CUSTOMIZATION.mdの規定値を使う。accentは--caroa-accent-foregroundとのコントラストも3変数一組で確認する | hover:bg-primary-hover / active:bg-primary-pressed、hover:bg-accent-action / active:bg-accent-pressed等。Buttonのvariantが参照する |
| 無効状態(disabled) | --caroa-disabled / --caroa-disabled-foreground | 0 0% 90% / 0 0% 54% | disabled:bg-disabled / disabled:text-disabled-foreground |
| 角丸 | --caroa-radius / --caroa-radius-sm / -md / -lg | 0.5rem / 0.25rem / 0.375rem / 0.5rem | rounded-sm / rounded-md / rounded-lg(rounded-l-md等の方向指定も含む) |
| 角丸(フル) | --caroa-radius-full | 9999px | 効かない。下記「変数化しない範囲」を参照 |
| シャドウ | --caroa-shadow-xs / -sm / -md / -lg | Tailwind v4組み込みデフォルトと同一 | shadow-xs / shadow-sm / shadow-md / shadow-lg |
| フォント | --caroa-font-sans / --caroa-font-mono | Tailwind v4組み込みデフォルトのシステムフォントスタック | font-sans / font-mono、および無指定時の既定フォント |
変数化しない範囲(意図的に対象外)
| 対象 | 理由 |
|---|---|
rounded-full | Tailwind v4がborder-radius: calc(infinity * 1px)にハードコードしており、CSS変数の上書きでは反映されません。アバターやピル形状など「完全な円」を保つべき要素はブランドが変わっても円のままにするのが望ましいため、意図的にテーマ対象から外しています。--caroa-radius-fullトークン自体は用意していますが、これはカスタムCSSやインラインスタイル用の参照値であり、rounded-fullユーティリティクラスは動かせません |
rounded-xl / rounded-2xl(一部コンポーネントの装飾的な角丸) | Lockedルール(角丸はrounded-lg以下)の例外として個別採用されている値。テーマ変数の対象外で、Tailwind組み込みの固定値のままです |
| 余白(padding/gap/spacing) | Baseの統一感を保つための構造的なルール。プロジェクトごとに変えるとコンポーネント間の整合が崩れるため対象外です |
| タイポグラフィ階層(type scale・weight system) | 4 Pillars(静寂性・優しさ・普遍性・ワクワク)を支える構造であり、Locked。フォント「ファミリー」だけがCustomizableです |
| レイアウト構造(コンポーネントの合成パターン、DOM構造) | UIライブラリとしての一貫性の根幹。個別上書きにはコンポーネントの再実装が必要です |
詳細な思想・Locked/Customizable区分はdesign-system/CUSTOMIZATION.mdを参照してください。
変数で届かない微調整の逃げ道
上記の変数で表現しきれない、コンポーネント単位のピンポイントな上書きが必要な場合は、data-caroa-ui / data-slotによるセレクタ上書きを使います(詳細は使い方ガイドの「data属性によるコンポーネント識別」を参照)。
/* 例: Select のトリガーだけ角丸を変える */
[data-caroa-ui][data-slot='select-trigger'] {
border-radius: 9999px;
}CSS変数のグローバル上書きより詳細度が高く、個別コンポーネントだけに効くため、Base全体のトーンを崩さずに例外対応できます。ただし多用するとBaseとの乖離が大きくなるため、まずは--caroa-*変数での対応を優先し、個別セレクタは最後の手段としてください。
アプリ側の運用
- プロジェクトの
DESIGN.mdに、theme.cssで上書きしている変数と理由を明記する(「上書きしない = Baseに従う」の原則どおり、書かれていない項目はBase準拠とみなされます) rounded-xl等、Lockedルールから意図的に逸脱する装飾パターンを使う場合は、アプリ側のdesign-check(lint)の例外リストに追記する(caroaship・thecast-portalの確立パターンに倣う)- Baseの更新(
pnpm update @caroainc/ui-components)後は、theme.cssの上書きが新しいデフォルト値と矛盾していないか確認する
useAutoThemeフックとの関係
ランタイムでテーマを動的に切り替えたい場合はカラーシステムにあるuseAutoThemeフックも使えます。既定テーマと同じ役割×tokenの組み合わせには、正本design-system/CUSTOMIZATION.mdで定めた状態色を適用し、それ以外のtokenには一貫したfallback値を導出します。accent指定時は--caroa-accent-action / --caroa-accent-pressedに加え、選択色からコントラストを判定した--caroa-accent-foregroundも更新します。borderRadius引数は内部で--caroa-radiusを書き換えるため、本ページの--caroa-radius-sm / -md / -lgの連動計算とそのまま組み合わせられます(互換性あり・非破壊)。