フロントエンド開発で「shadcn/uiとTailwind CSSって何が違うの?」という疑問を持ったことはないでしょうか。どちらもReact周辺でよく名前が挙がり、見た目の話をしている点では共通しているため、最初は混同しやすいものです。本記事では、両者の役割の違いと正しい使い分けを整理します。
そもそもTailwind CSSとは何か
Tailwind CSSは、ユーティリティファーストのCSSフレームワークです。flex、pt-4、text-centerといった小さなクラスを組み合わせてスタイリングを行う設計思想を持っています。2024年末にリリースされたv4では、CSS-firstの設定方式へと大きく進化しました。
Tailwind CSSの本質は「スタイリングの手段」です。ボタンやカードといったUIコンポーネントそのものは提供しません。あくまで、HTMLの要素に対して見た目を定義するための語彙を提供するレイヤーに位置しています。
私自身、最初にTailwind CSSに触れたとき「クラス名が長くなりすぎて読みにくいのでは」と感じました。しかし実際にプロジェクトで使い込むと、CSSファイルを行き来する認知コストが大幅に減り、開発速度が向上する実感がありました。Tailwind CSSの公式ドキュメントによれば、ユーティリティクラスのアプローチはコンポーネント指向の開発と相性が良く、スタイルの重複やCSS肥大化を構造的に抑制できるとされています。
従来のCSS設計手法との比較
Tailwind CSSの位置づけをより明確にするために、従来のCSS設計手法と比較してみましょう。BEM(Block Element Modifier)やCSS Modulesなど、これまでもCSSの管理を改善するアプローチは数多く存在していました。
たとえば、BEMでは以下のようにクラス名を命名します。
<button class="button button--primary button--large">
送信する
</button>.button { padding: 8px 16px; border-radius: 4px; }
.button--primary { background-color: #3b82f6; color: white; }
.button--large { padding: 12px 24px; font-size: 1.125rem; }同じボタンをTailwind CSSで記述すると、次のようになります。
<button class="rounded bg-blue-500 px-6 py-3 text-lg text-white">
送信する
</button>BEMではクラス名の設計に頭を使い、CSSファイルにルールを定義する必要がありますが、Tailwind CSSではHTML上で直接スタイルを完結させられます。この違いは小さなボタン一つでは些細に感じるかもしれません。しかし、数十画面・数百コンポーネントを抱えるプロジェクトになると、CSSファイルの肥大化やクラス名の衝突といった問題が顕在化しにくいTailwind CSSの恩恵を強く感じるようになります。
CSS Modulesはスコープの問題を解決してくれますが、ファイルを分離して管理する手間は残ります。Tailwind CSSは「そもそもカスタムCSSをほとんど書かない」というアプローチで、この課題を根本から回避しているわけです。
Tailwind CSS v4で変わったこと
2024年末にリリースされたv4は、設定方法に大きな変更がありました。従来のtailwind.config.jsによるJavaScriptベースの設定から、CSSファイル内で直接設定を記述する「CSS-first」の方式に移行しています。
/* v4のCSS-first設定 */
@import "tailwindcss";
@theme {
--color-brand: #3b82f6;
--font-display: "Inter", sans-serif;
}従来のv3では、JavaScriptの設定ファイルにテーマのカスタマイズを記述していました。v4ではCSSカスタムプロパティ(CSS変数)を中心とした設計に変わり、設定とスタイルが同じ言語で完結するようになっています。この変更により、ビルドツールとの統合がシンプルになり、設定の見通しがよくなったと感じています。
また、v4では自動コンテンツ検出が導入され、content配列を手動で指定する必要がなくなりました。プロジェクト内のファイルを自動的にスキャンしてくれるため、設定の記述量が大幅に減っています。
shadcn/uiとは何か——「ライブラリではない」という設計
shadcn/uiは、Radix UIとTailwind CSSをベースに構築されたUIコンポーネント集です。ここで重要なのは、shadcn/uiは一般的なnpmパッケージとしてインストールするUIライブラリではないという点です。
npx shadcn@latest add buttonのようなコマンドを実行すると、ボタンコンポーネントのソースコードがプロジェクト内にコピーされます。つまり、依存関係としてnode_modulesに入るのではなく、自分のコードベースの一部になるのです。この「コピー&オウン」というアプローチは、UIコンポーネントの所有権を開発者に委ねる設計思想に基づいています。
MUIやAnt Designのようなコンポーネントライブラリでは、提供されるAPIの範囲内でカスタマイズを行います。デザインの自由度とライブラリの制約の間で悩んだ経験のある方も多いのではないでしょうか。shadcn/uiではコード自体が手元にあるため、プロジェクト固有の要件に合わせた改変が自然にできます。
アクセシビリティの面では、内部的にRadix UIのプリミティブを利用しているため、WAI-ARIAパターンへの準拠がベースラインとして確保されています。キーボード操作やスクリーンリーダー対応をゼロから実装する必要がないのは、実務上の大きなメリットです。
コピーされるコードの具体例
実際にshadcn/uiのButtonコンポーネントがどのようなコードなのか、簡略化した形で見てみましょう。
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent",
ghost: "hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)ここで注目すべき点がいくつかあります。まず、cva(class-variance-authority)というライブラリを使って、バリアント(variant)ごとのスタイルを宣言的に管理しています。bg-primaryやtext-primary-foregroundといったクラスはすべてTailwind CSSのユーティリティクラスです。つまり、shadcn/uiのコンポーネントを読み解くには、Tailwind CSSの知識が前提になります。
また、SlotコンポーネントはRadix UIが提供するもので、asChildパターンを実現しています。これにより、ボタンの見た目を保ちながら、内部の要素を<a>タグなど任意の要素に差し替えることが可能です。
{/* 通常のボタン */}
<Button variant="default">クリック</Button>
{/* リンクとして振る舞うボタン */}
<Button asChild>
<a href="/dashboard">ダッシュボードへ</a>
</Button>このコードはすべて自分のプロジェクト内にあるため、たとえば「destructiveバリアントの色を変更したい」「新しいバリアントを追加したい」といった要求にも、ファイルを直接編集するだけで対応できます。ライブラリのIssueを立てたり、テーマのオーバーライド方法を調べたりする必要はありません。
Radix UIが担っている役割
shadcn/uiを理解するうえで欠かせないのが、Radix UIの存在です。Radix UIは「ヘッドレスUIライブラリ」と呼ばれ、見た目のスタイルを一切持たず、コンポーネントの振る舞いとアクセシビリティだけを提供します。
たとえば、ドロップダウンメニューを自前で実装するとしましょう。開閉の状態管理、キーボードでの項目移動、Escキーでの閉じ処理、フォーカストラップ、aria-expanded属性の制御など、考慮すべきことは多岐にわたります。これらをすべて正しく実装するのは、実は相当な労力です。
Radix UIはこうした「見えない複雑さ」を抽象化してくれます。shadcn/uiは、Radix UIが提供するアクセシブルな振る舞いの上に、Tailwind CSSで見た目を付与したものだと捉えるとわかりやすいでしょう。
Radix UI(振る舞い・アクセシビリティ)
↑ 利用
shadcn/ui(コンポーネント構造・スタイル定義)
↑ 利用
Tailwind CSS(ユーティリティクラスによるスタイリング)この三層構造を理解しておくと、問題が発生したときに原因の切り分けがしやすくなります。スタイルの問題ならTailwind CSSの設定を確認し、振る舞いの問題ならRadix UIのドキュメントを参照する、といった具合です。
両者の関係——レイヤーの違いを理解する
ここが最も重要なポイントです。Tailwind CSSとshadcn/uiは競合するものではなく、技術スタックの異なるレイヤーに位置しています。
| 観点 | Tailwind CSS | shadcn/ui |
|---|---|---|
| 役割 | スタイリング基盤 | UIコンポーネント集 |
| 提供するもの | ユーティリティクラス | コピー可能なコンポーネントコード |
| 導入形態 | npmパッケージ(依存関係) | CLIによるソースコードコピー |
| 単独で使えるか | はい | いいえ(Tailwind CSS等が必要) |
| フレームワーク依存 | なし(どのFWでも利用可) | React(Next.js推奨) |
shadcn/uiのコンポーネント内部を見ると、Tailwind CSSのユーティリティクラスでスタイリングされていることがわかります。つまり、shadcn/uiはTailwind CSSの上に構築されたコンポーネント層であり、「Tailwind CSSか、shadcn/uiか」という二者択一の問いは成り立ちません。
振り返ると、私も最初はこの関係性を見落としていました。「どちらを採用すべきか」と比較していた時期がありましたが、正しくは「Tailwind CSSを採用した上で、コンポーネント層にshadcn/uiを使うかどうか」という判断になります。
建築に例えると
技術的な話が続いたので、身近な例えで整理してみます。建築で考えると、Tailwind CSSは「レンガやタイルといった建材」に相当します。それ単体では建物にはなりませんが、あらゆる構造物を作るための基本素材です。
一方、shadcn/uiは「設計図付きのプレカット部材」のようなものです。ドアや窓枠といった、よく使われるパーツの設計図とカット済みの部材が提供され、そのまま使うこともできれば、現場の寸法に合わせて加工することもできます。そしてその部材自体は、レンガやタイル(Tailwind CSS)で構成されています。
この例えを聞いて「ではMUIやChakra UIは何に当たるのか」と思われるかもしれません。これらは「既製品の建売住宅」に近いイメージです。すぐに使える完成度の高さがある反面、壁を取り払って間取りを変えるような大幅な改変には制約が伴います。
他のUIライブラリとの違い
shadcn/uiの特徴をより深く理解するために、よく比較される他のUIライブラリとの違いを見てみましょう。
MUI(Material UI)との比較
MUIはGoogleのMaterial Designガイドラインに基づいたコンポーネントライブラリです。npmパッケージとしてインストールし、提供されるAPIを通じてコンポーネントを利用します。
{/* MUIのボタン */}
<Button variant="contained" color="primary" size="large">
送信する
</Button>MUIの強みは、Material Designという確立されたデザインシステムに準拠している点と、豊富なコンポーネントがすぐに使える点です。一方で、Material Designから離れた独自のデザインを実現しようとすると、sxプロパティやテーマのオーバーライドが複雑になりがちです。
私自身、過去のプロジェクトでMUIのDatePickerのデザインを大幅にカスタマイズしようとして、かなりの時間を費やした経験があります。内部のDOM構造を把握し、適切なクラス名を指定してスタイルを上書きする作業は、ドキュメントを何度も往復する骨の折れる作業でした。
shadcn/uiであれば、DatePickerのコードそのものが手元にあるため、こうした「ライブラリの壁」にぶつかることがありません。ただし、その代わりにコンポーネントの更新を自分で管理する責任が生じます。
Headless UIライブラリとの比較
Radix UI、Headless UI(Tailwind Labs製)、Ariadkit(現Ariakit)などのヘッドレスUIライブラリは、見た目を持たずに振る舞いだけを提供します。
shadcn/uiはこれらのヘッドレスUIライブラリ(主にRadix UI)の上にスタイルを付与したものなので、「ヘッドレスUIを自分でスタイリングする手間を省いてくれるスターターキット」とも言えます。
ヘッドレスUIを直接使う場合、すべてのスタイリングを自分で行う必要があります。デザインの自由度は最大ですが、それなりの工数がかかります。shadcn/uiは、その中間に位置する選択肢として、実用的なデフォルトスタイルと完全なカスタマイズ性の両方を提供しているわけです。
プロジェクトでの使い分けと判断基準
実際のプロジェクトでどう選択すべきか、いくつかのパターンを整理します。
Tailwind CSSのみで十分なケースとして、デザインの独自性が高くコンポーネントを自前で組みたい場合や、React以外のフレームワーク(Vue、Svelte等)を採用している場合が挙げられます。また、既存のデザインシステムがあり、それに準拠したコンポーネントを構築する場合もこちらに該当するでしょう。
shadcn/uiの併用が効果的なケースとしては、Next.js/Reactプロジェクトで管理画面やダッシュボードを素早く構築したい場合があります。アクセシブルなコンポーネントを効率よく揃えたい場合や、デザインの一貫性を保ちつつカスタマイズ性も確保したい場合にも有効です。
一概には言えない部分もありますが、判断の軸としては「コンポーネントの所有権をどこに置くか」が重要だと感じています。外部ライブラリに依存してバージョンアップに追従するコストを受け入れるか、自前のコードとして管理する責任を負うか。shadcn/uiは後者のアプローチを明確に支持しており、この思想に共感できるかどうかが採用の分かれ目になるかもしれません。
具体的な判断フローチャート
もう少し具体的に、プロジェクト開始時の判断フローを整理してみます。
1. フレームワークの確認 Reactを使っていない場合、shadcn/uiは選択肢に入りません。Vue、Svelte、Astro(Reactなし)などのプロジェクトでは、Tailwind CSSを直接使うか、各フレームワーク向けのUIライブラリを検討します。
2. デザインの方向性 すでに確立されたデザインシステム(Material Designなど)に準拠する必要がある場合は、そのデザインシステムに対応したライブラリ(MUIなど)が適しています。独自のデザインを構築する場合や、デザインの自由度を優先する場合は、Tailwind CSS + shadcn/uiの組み合わせが力を発揮します。
3. プロジェクトの性質 管理画面やダッシュボードのように、標準的なUIパターン(テーブル、フォーム、モーダルなど)を多用する場合、shadcn/uiのコンポーネントをそのまま活用できるため効率的です。一方、マーケティングサイトやランディングページのように、ページごとにデザインが大きく異なる場合は、Tailwind CSSで直接スタイリングしたほうが小回りが利くこともあります。
4. チームのスキルセット Tailwind CSSの経験が浅いチームの場合、shadcn/uiの既成コンポーネントから始めることで、Tailwind CSSのクラスの組み合わせ方を学ぶ足がかりになります。実際に私たちのプロジェクトでも、shadcn/uiのコンポーネントコードを読むことでTailwind CSSの実践的なパターンを理解したメンバーがいました。
shadcn/ui導入時の実践的なTips
実際にshadcn/uiをプロジェクトに導入する際に知っておくと助かるポイントをいくつか共有します。
必要なコンポーネントだけを追加する。 shadcn/uiは「全部入り」でインストールするものではありません。npx shadcn@latest add button dialog tableのように、その時点で必要なものだけを追加し、必要になったタイミングで都度追加していくのが推奨される使い方です。不要なコードを抱えないことで、プロジェクトの見通しを保てます。
テーマカラーのカスタマイズはCSS変数で行う。 shadcn/uiはCSS変数(--primary、--backgroundなど)でテーマを管理しています。ブランドカラーへの変更は、これらの変数を書き換えるだけで全コンポーネントに一括反映されます。各コンポーネントのクラス名を個別に変更する必要はありません。
@layer base {
:root {
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
/* ブランドカラーに合わせて値を変更する */
}
}コンポーネントを改変したら、その意図をコメントで残す。 コピーされたコードは自分のものですが、元のshadcn/uiのコードから何を変更したかがわかるようにしておくと、将来shadcn/uiが新しいコンポーネントを追加したときに、差分を把握しやすくなります。
よくある誤解と注意点
shadcn/uiとTailwind CSSについて、現場でよく見かける誤解をいくつか取り上げます。
「shadcn/uiを入れればTailwind CSSは不要」という誤解
これは最も多い誤解のひとつです。前述の通り、shadcn/uiのコンポーネントはTailwind CSSのユーティリティクラスでスタイリングされています。shadcn/uiを使うということは、必然的にTailwind CSSも使うということです。shadcn/uiの導入ガイドでも、前提としてTailwind CSSのセットアップが求められています。
「コピーしたコードは更新されない」という不安
shadcn/uiの「コピー&オウン」モデルに対して、「本家が更新されても手元のコードに反映されないのでは」という懸念をお持ちの方もいるでしょう。これは事実ですが、むしろそれが設計上の意図です。
一般的なUIライブラリでは、メジャーバージョンアップ時に破壊的変更への対応が必要になることがあります。過去にMUIのv4からv5への移行で苦労された方も少なくないはずです。shadcn/uiでは、手元にコピーしたコードが動いている限り、本家の変更に追従する義務がありません。もちろん、新しいコンポーネントや改善を取り入れたい場合は、再度CLIで追加したり、差分を手動で適用したりすることができます。
「Tailwind CSSはインラインスタイルと同じ」という批判
Tailwind CSSに対して「結局インラインスタイルと変わらないのでは」という指摘を見かけることがあります。確かに、HTMLにスタイル情報を直接記述するという点では似ているように見えます。しかし、両者には重要な違いがあります。
Tailwind CSSのユーティリティクラスは、デザイントークン(間隔、色、タイポグラフィなどの規定値)に基づいています。p-4は常に1remのパディングを意味し、text-blue-500は常に同じ青色を指します。この制約があることで、デザインの一貫性が自然と保たれます。インラインスタイルには、こうした制約の仕組みがありません。
さらに、Tailwind CSSはレスポンシブデザイン(md:flex)、ホバー状態(hover:bg-blue-600)、ダークモード(dark:bg-gray-800)といった擬似クラスやメディアクエリにも対応しています。これらはインラインスタイルでは実現できない機能です。
まとめ——正しい理解が技術選定の質を上げる
Tailwind CSSはスタイリングのための基盤技術、shadcn/uiはその上に構築されたコンポーネント提供の仕組みです。両者はレイヤーが異なるため比較対象ではなく、むしろ組み合わせて使うことが前提となっています。
改めて整理すると、技術スタックの中での位置づけは以下の通りです。
- Tailwind CSS → CSSを書くための語彙とデザイントークンを提供する基盤
- Radix UI → アクセシビリティと振る舞いを担うヘッドレスUIレイヤー
- shadcn/ui → 上記二つを組み合わせ、実用的なコンポーネントとして手元に届ける仕組み
この三層構造を理解しておけば、「どちらを選ぶべきか」という問い自体が的外れであることがわかります。正しい問いは「Tailwind CSSの上に、どのコンポーネント戦略を採るか」であり、その選択肢の一つとしてshadcn/uiがあるということです。
フロントエンドのエコシステムは選択肢が多く、似た名前のツールが次々と登場するため、それぞれの役割を正確に把握することが技術選定の精度に直結します。本記事が、日々の開発における判断の一助になれば幸いです。
aduceでは、こうしたフロントエンド技術の選定から実装まで、プロジェクトに最適なアプローチをご提案しています。技術選定やUI設計でお悩みの際は、aduceのお問い合わせはこちらからお気軽にご相談ください。
