shadcn/ui で管理画面の骨組みを構築:Sidebar + Layout ベストプラクティス
管理画面の拡張しやすい骨組みを、Sidebar コンポーネントから Next.js Layout の統合まで手を動かして構築します。完全なコードはそのまま使えます。
先週、管理画面システムの案件を引き受けました。真っ先に思い浮かんだのが shadcn/ui です。正直なところ、これまで Ant Design や MUI を使ってきて、スタイルのカスタマイズには毎回手こずる印象がありました。大量のスタイルを上書きするか、フレームワークのデザイン思想に縛られるか、どちらかになりがちだったのです。
shadcn/ui は違います。「Copy-paste」方式で、コードを直接プロジェクトに置くので、好きなように手を入れられます。2 週間使ってみて、これは確かに快適だと実感しました。特に Sidebar コンポーネントは、Next.js の App Router と組み合わせると、管理画面の骨組みがぐっとすっきり仕上がります。
この記事では、その実践プロセスを整理します。ゼロから始めて、拡張しやすい管理画面レイアウトを一緒に構築していきましょう。
一、なぜ shadcn/ui Sidebar を選ぶのか?
まずは私がハマってきた落とし穴から話します。
以前 Ant Design Pro を使ったときは、すぐ使えて確かに快適でした。ただ、プロジェクトが長く続くと頭が痛くなってきます。サイドバーのスタイルを変えたいだけでもドキュメントを延々と探す羽目になり、ちょっとした独自のインタラクションを入れようとすると、フレームワークの制約が多すぎることに気づきます。MUI にも似た問題がありました。テーマのカスタマイズは柔軟だと言われますが、それは Material Design を書けるという前提があってこそです。
従来手法の悩みどころ
Ant Design:機能は豊富ですが、カスタマイズのコストが高い。サイドバーの角丸を変えたいだけで、3 層分のスタイル上書きを書くことになったりします。
MUI:デザイン体系は完成されていますが、学習曲線が急。Styled Components の書き方は、チームの新人が慣れるのに 1 週間ほどかかります。
自前で実装:完全にコントロールできますが、レスポンシブ、アクセシビリティ、キーボード操作に対応したサイドバーをゼロから書くとなると、少なく見積もっても 3 日はかかります。
shadcn/ui の解き方
shadcn/ui は別の道を選んでいます:
- Copy-paste 方式:コンポーネントのコードを直接プロジェクトに置くので、ブラックボックスな依存がありません
- Radix UI ベース:アクセシビリティが組み込み済み。キーボード操作や ARIA 属性は最初から処理してくれます
- Tailwind CSS 駆動:スタイルはクラス名そのもの。好きなように変えられ、スタイル上書きの煩わしさがありません
MUI から shadcn/ui へ移行したチームを何組も見てきました。理由はシンプルです。彼らが欲しいのは「コントロールできること」であって、すぐ使えるテンプレートではないのです。
向いている場面
次のようなものを作っているなら:
- 中小規模の管理画面システム
- SaaS プロダクトのコンソール
- 社内ツールや運用プラットフォーム
shadcn/ui Sidebar は試す価値があります。完成された管理画面テンプレートをくれるわけではありませんが、十分に柔軟な骨組みを与えてくれます。
二、Sidebar コンポーネントの構成を理解する
手を動かす前に、shadcn/ui Sidebar のコンポーネント体系を理解しておきましょう。ここは公式ドキュメントでも比較的わかりやすく書かれている部分なので、ざっと一通り見ていきます。
主要コンポーネント一覧
Sidebar は一連のコンポーネントから成り、それぞれが役割を分担します:
SidebarProvider // 状態のコンテキスト。アプリ全体をラップ
Sidebar // サイドバーのコンテナ
SidebarHeader // 上部の固定エリア。Logo を置く
SidebarContent // スクロール可能なコンテンツ領域。メニューを置く
SidebarGroup // メニューのグループ
SidebarMenu // メニューのリスト
SidebarMenuItem // メニュー項目
SidebarMenuButton // メニューボタン(Link 対応)
SidebarFooter // 下部の固定エリア。ユーザー情報を置く
SidebarTrigger // 折りたたみ/展開ボタン
SidebarInset // メインコンテンツ領域のラッパー
コンポーネントは多く見えますが、関係はとても明快です:
SidebarProvider
├── Sidebar
│ ├── SidebarHeader
│ ├── SidebarContent
│ │ └── SidebarGroup
│ │ └── SidebarMenu
│ │ └── SidebarMenuItem
│ │ └── SidebarMenuButton
│ └── SidebarFooter
└── SidebarInset
└── {children}
状態管理の仕組み
Sidebar の折りたたみ状態は SidebarProvider が管理します。モードは 2 つあります:
非制御モード(おすすめ):
<SidebarProvider defaultOpen={true}>
<Sidebar />
</SidebarProvider>
制御モード:
const [open, setOpen] = useState(true);
<SidebarProvider open={open} onOpenChange={setOpen}>
<Sidebar />
</SidebarProvider>
ほとんどの場合は非制御モードで十分です。別の場所から Sidebar の状態をコントロールしたい(たとえばユーザー設定にトグルがあるなど)ときだけ、制御モードを使いましょう。
レスポンシブ設計の原理
Sidebar にはレスポンシブ対応が組み込まれています:
- デスクトップ:サイドバーは左側に固定され、
SidebarTriggerで折りたためます - モバイル:自動的にドロワー式(Sheet)になり、Trigger をタップすると表示されます
このロジックはコンポーネントの内部で処理されます。あなたは SidebarProvider で設定しておくだけで、あとはコンポーネントに任せられます。
三、Next.js Layout との統合実践
さて、コアとなる概念は説明し終わりました。次がいよいよ本題です。Sidebar を Next.js の Layout システムに統合していきます。
3.1 プロジェクト構成の設計
Next.js の Route Groups でレイアウトを整理するのがおすすめです。こうすると、機能ごとに異なるレイアウトを持たせつつ、URL 構造には影響を与えずに済みます。
app/
├── layout.tsx # Root Layout(全体)
├── (marketing)/ # マーケティングページ群(Landing、About)
│ ├── layout.tsx # Sidebar なし
│ └── page.tsx # トップページ
├── (dashboard)/ # 管理画面ページ群
│ ├── layout.tsx # Sidebar 付きのレイアウト
│ ├── page.tsx # Dashboard ホーム
│ ├── users/
│ │ └── page.tsx # ユーザー管理
│ └── settings/
│ └── page.tsx # システム設定
└── (auth)/ # 認証ページ群
├── layout.tsx # 中央寄せレイアウト
├── login/
│ └── page.tsx # ログインページ
└── register/
└── page.tsx # 登録ページ
この構成のよいところは次のとおりです:
- レイアウトの分離:マーケティングページには Sidebar が不要、管理画面ページには必要。Route Groups で自然に分けられます
- URL がシンプル:
(dashboard)は URL に現れないので、/usersはそのまま/usersです - 拡張しやすい:ページ群を増やすときはフォルダを新しく作るだけです
3.2 Root Layout の設定
Root Layout はアプリ全体の入り口です。ここで全体に関わるもの、つまりテーマ、フォント、SidebarProvider を設定します。
// app/layout.tsx
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { SidebarProvider } from "@/components/ui/sidebar";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Admin Dashboard",
description: "Built with shadcn/ui and Next.js",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="zh-CN">
<body className={inter.className}>
<SidebarProvider>
{children}
</SidebarProvider>
</body>
</html>
);
}
ここで SidebarProvider を Dashboard Layout ではなく Root Layout に置いている点に注目してください。こうすると Sidebar の状態がページをまたいで保持されます(たとえば /users から /settings へ移動しても、折りたたみ状態が失われません)。
3.3 Dashboard Layout の実装
Dashboard Layout は管理画面の中心となるレイアウトで、Sidebar はここで導入します。
// app/(dashboard)/layout.tsx
import { AppSidebar } from "@/components/app-sidebar";
import { SidebarInset, SidebarTrigger } from "@/components/ui/sidebar";
import { Separator } from "@/components/ui/separator";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<>
<AppSidebar />
<SidebarInset>
<header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
<SidebarTrigger className="-ml-1" />
<Separator orientation="vertical" className="mr-2 h-4" />
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem className="hidden md:block">
<BreadcrumbLink href="/dashboard">
管理画面
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator className="hidden md:block" />
<BreadcrumbItem>
<BreadcrumbPage>概要</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</header>
<main className="flex-1 p-4 pt-6">{children}</main>
</SidebarInset>
</>
);
}
このレイアウトには次のものが含まれます:
- AppSidebar:自作のサイドバーコンポーネント(次の節で実装します)
- SidebarInset:メインコンテンツ領域のラッパー。Sidebar 折りたたみ時の幅を自動で処理します
- Header:上部のナビゲーションバー。SidebarTrigger とパンくずを含みます
- Main:メインコンテンツ領域
3.4 AppSidebar コンポーネントの実装
いよいよサイドバー本体を実装します。設定駆動の方式がおすすめです。ナビゲーションメニューを設定ファイルに置き、コンポーネントが設定に基づいてレンダリングします。
まずはナビゲーション設定を定義します:
// lib/navigation.ts
import {
Home,
Users,
Settings,
FileText,
BarChart3,
Shield,
} from "lucide-react";
export interface NavItem {
title: string;
href: string;
icon: React.ComponentType<{ className?: string }>;
badge?: string;
}
export const navConfig: NavItem[] = [
{
title: "概要",
href: "/dashboard",
icon: Home,
},
{
title: "ユーザー管理",
href: "/users",
icon: Users,
badge: "12", // バッジ
},
{
title: "データ分析",
href: "/analytics",
icon: BarChart3,
},
{
title: "コンテンツ管理",
href: "/content",
icon: FileText,
},
{
title: "システム設定",
href: "/settings",
icon: Settings,
},
{
title: "権限管理",
href: "/permissions",
icon: Shield,
},
];
続いて AppSidebar を実装します:
// components/app-sidebar.tsx
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from "@/components/ui/sidebar";
import { navConfig } from "@/lib/navigation";
import { Logo } from "@/components/logo";
import { UserNav } from "@/components/user-nav";
export function AppSidebar() {
const pathname = usePathname();
return (
<Sidebar>
<SidebarHeader className="border-b border-border">
<Logo />
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>ナビゲーションメニュー</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{navConfig.map((item) => {
const isActive = pathname === item.href;
return (
<SidebarMenuItem key={item.href}>
<SidebarMenuButton
asChild
isActive={isActive}
tooltip={item.title}
>
<Link href={item.href}>
<item.icon className="h-4 w-4" />
<span>{item.title}</span>
{item.badge && (
<span className="ml-auto text-xs bg-primary text-primary-foreground rounded-full px-2 py-0.5">
{item.badge}
</span>
)}
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
);
})}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter className="border-t border-border">
<UserNav />
</SidebarFooter>
</Sidebar>
);
}
ここで重要なのが ルートのハイライト です。usePathname() で現在のパスを取得し、item.href と比較します。一致したら SidebarMenuButton に isActive={true} を渡すと、コンポーネントが自動的にアクティブ状態のスタイルを適用してくれます。
3.5 多階層メニューの実装
管理画面に 2 階層目のメニューがある場合は、Collapsible で SidebarGroup をラップできます:
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { ChevronDown } from "lucide-react";
// SidebarMenu の中で
<Collapsible defaultOpen>
<SidebarMenuItem>
<CollapsibleTrigger asChild>
<SidebarMenuButton>
<Settings className="h-4 w-4" />
<span>システム設定</span>
<ChevronDown className="ml-auto h-4 w-4 transition-transform group-data-[state=open]/collapsible:rotate-180" />
</SidebarMenuButton>
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
<SidebarMenuSubItem>
<SidebarMenuSubButton href="/settings/general">
<span>基本設定</span>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
<SidebarMenuSubItem>
<SidebarMenuSubButton href="/settings/security">
<span>セキュリティ設定</span>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenuItem>
</Collapsible>
四、応用機能の実装
基本のレイアウトができたので、次は実用的な応用機能を見ていきましょう。
4.1 権限制御(RBAC)
多くの管理画面では、ユーザーの役割に応じて表示するメニューを変える必要があります。実装はとてもシンプルです。ナビゲーション設定に roles フィールドを足し、レンダリング時にフィルタするだけです。
まずは設定を改修します:
// lib/navigation.ts
export interface NavItem {
title: string;
href: string;
icon: React.ComponentType<{ className?: string }>;
roles?: string[]; // アクセスを許可する役割
}
export const navConfig: NavItem[] = [
{
title: "概要",
href: "/dashboard",
icon: Home,
// roles を設定しない=全員に表示
},
{
title: "ユーザー管理",
href: "/users",
icon: Users,
roles: ["admin", "manager"], // admin と manager だけに表示
},
{
title: "権限管理",
href: "/permissions",
icon: Shield,
roles: ["admin"], // admin だけに表示
},
];
続いて AppSidebar 内で、ユーザーの役割に応じてフィルタします:
// components/app-sidebar.tsx
import { useAuth } from "@/hooks/use-auth"; // auth フックがある前提
export function AppSidebar() {
const pathname = usePathname();
const { user } = useAuth(); // 現在のユーザーを取得
const filteredNav = navConfig.filter((item) => {
if (!item.roles) return true; // 役割制限なし=全員に表示
return item.roles.some((role) => user?.roles?.includes(role));
});
return (
<Sidebar>
{/* ... */}
<SidebarMenu>
{filteredNav.map((item) => {
// ...
})}
</SidebarMenu>
{/* ... */}
</Sidebar>
);
}
これで、一般ユーザーがログインしても「権限管理」のメニュー項目は見えなくなります。
4.2 外部リンクと区切り線
サイドバーに外部リンク(ドキュメントやヘルプセンターなど)を置きたいときや、区切り線でメニューをグループ分けしたいときもあります。shadcn/ui Sidebar はこれにも対応しています:
<SidebarGroup>
<SidebarGroupLabel>主な機能</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{/* 主なメニュー項目 */}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>ヘルプとサポート</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<a href="https://docs.example.com" target="_blank" rel="noopener">
<BookOpen className="h-4 w-4" />
<span>ドキュメント</span>
<ExternalLink className="ml-auto h-3 w-3" />
</a>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<a href="mailto:support@example.com">
<HelpCircle className="h-4 w-4" />
<span>お問い合わせ</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
4.3 検索ボックスとクイック操作
多くの管理画面では、サイドバーに検索ボックスやグローバル検索(Cmd+K)を置きます。shadcn/ui には Command コンポーネントがあり、これを実現できます:
import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from "@/components/ui/command";
<SidebarGroup>
<SidebarGroupContent>
<Command className="rounded-lg border shadow-md">
<CommandInput placeholder="メニューを検索..." />
<CommandList>
<CommandEmpty>結果が見つかりません</CommandEmpty>
<CommandGroup heading="候補">
{navConfig.map((item) => (
<CommandItem key={item.href} onSelect={() => router.push(item.href)}>
<item.icon className="mr-2 h-4 w-4" />
{item.title}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</SidebarGroupContent>
</SidebarGroup>
五、パフォーマンス最適化とベストプラクティス
最後に、実践で役立つ最適化のポイントをいくつか取り上げます。
Server Components を優先する
Next.js App Router では、デフォルトですべてのコンポーネントが Server Component です。Sidebar の静的な部分(Logo や固定のメニュー項目など)は Server Component のままにしておき、インタラクションが必要な部分(ルートのハイライト、折りたたみ状態)だけ "use client" にできます。
私のやり方は次のとおりです:
AppSidebarは"use client"を付ける(usePathnameを使うため)SidebarHeader、SidebarFooter内の静的な部分は別の Server Component に切り出す- ナビゲーション設定はサーバー側で生成し、クライアントコンポーネントに渡す
こうするとクライアント側の JS サイズを減らせます。
大規模メニューの遅延読み込み
管理画面にメニュー項目が数十個あるなら、遅延読み込みを検討してもよいでしょう。React.lazy または Next.js の dynamic を使います:
import dynamic from "next/dynamic";
const AdminMenu = dynamic(() => import("./admin-menu"), {
loading: () => <SidebarMenuSkeleton />,
});
とはいえ正直なところ、ほとんどの管理画面はメニュー項目がそこまで多くならないので、この最適化が役立つ場面はあまりありません。
アクセシビリティのポイント
shadcn/ui の Sidebar は Radix UI ベースなので、アクセシビリティは基本的に組み込まれています。ただ、それでも気をつけたい点がいくつかあります:
- アイコン + 文字:アイコンだけにしないこと。スクリーンリーダーのユーザーには見えません
- フォーカスを見えるように:デフォルトのフォーカススタイルを上書きしないこと
- キーボード操作:Tab と方向キーがきちんと動くようにすること
Radix UI が大部分を処理してくれますが、コンポーネントを自分でカスタマイズしたときは、キーボード操作を必ずテストしておきましょう。
六、よくある質問
Q1: Sidebar の状態がリロード後に失われる?
SidebarProvider を Root Layout ではなく Dashboard Layout に置いていると、ルート切り替え時に状態がリセットされます。Provider を Root Layout に引き上げれば解決します。
Q2: モバイルで Sidebar を自動的に閉じるには?
shadcn/ui の Sidebar はモバイルで自動的に Sheet になります。メニュー項目をタップした後に、自分で閉じる処理を呼ぶ必要があります:
const { setOpenMobile } = useSidebar();
<SidebarMenuButton
onClick={() => setOpenMobile(false)}
>
Q3: Sidebar の幅をカスタマイズするには?
CSS 変数を使います:
<Sidebar
style={{
"--sidebar-width": "280px",
"--sidebar-width-mobile": "100%",
}}
>
または sidebar.tsx の SIDEBAR_WIDTH 定数を変更します。
まとめ
shadcn/ui Sidebar と Next.js Layout を組み合わせると、管理画面の骨組みを効率よく構築できます。要点を振り返りましょう:
- コンポーネント体系:SidebarProvider、Sidebar、SidebarContent などの役割を理解する
- Layout の統合:Route Groups でレイアウトを分離し、
SidebarProviderは Root Layout に置く - 設定駆動:ナビゲーションメニューを設定ファイルに置き、コンポーネントが設定に基づいてレンダリング。保守が楽になる
- ルートのハイライト:
usePathname()+isActiveprop で、シンプルかつ直接的に - 権限制御:設定に
rolesを足し、レンダリング時にフィルタする
この構成はいくつものプロジェクトで使ってきましたが、拡張性はなかなか優秀です。ページを追加するときは navConfig に 1 行足すだけで、あとはコンポーネントが処理してくれます。
質問があればコメント欄で気軽にどうぞ。次回は shadcn/ui DataTable の実践的な使い方を書く予定です。興味があればフォローしてみてください。
参考資料
shadcn/ui Sidebar + Next.js Layout で管理画面の骨組みを構築する
サイドバー、ルートのハイライト、権限制御を含む、拡張しやすい管理画面のレイアウトをゼロから構築します
⏱️ 目安時間: 45 分
- 1
ステップ1: shadcn/ui を導入し Sidebar コンポーネントを追加する
CLI コマンドを実行してプロジェクトを初期化し、コンポーネントを追加します:
```bash
npx shadcn@latest init
npx shadcn@latest add sidebar
```
インストール中にスタイル設定を聞かれますが、デフォルトのままで構いません。完了すると components/ui ディレクトリに sidebar.tsx が生成されます。 - 2
ステップ2: Root Layout を設定する
app/layout.tsx で SidebarProvider をラップします:
• SidebarProvider コンポーネントをインポート
• body タグ内で {children} をラップ
• lang="zh-CN" の言語属性を設定
こうすると Sidebar の状態がアプリ全体で永続化されます。 - 3
ステップ3: Dashboard Layout を作成する
app/(dashboard)/layout.tsx に管理画面専用のレイアウトを作成します:
• Route Groups 構文 (dashboard) を使用
• AppSidebar と SidebarInset を導入
• 上部の Header とパンくずナビゲーションを追加
Route Groups は URL 構造に影響しないため、/dashboard のパスはそのままルートパスにマッピングされます。 - 4
ステップ4: ナビゲーション設定を定義する
lib/navigation.ts の設定ファイルを作成します:
• NavItem インターフェースを定義(title、href、icon、badge)
• navConfig 配列をエクスポート
• 必要に応じて roles フィールドを追加し権限制御を実装
設定駆動にすると、メニュー追加は 1 か所を直すだけで済みます。 - 5
ステップ5: AppSidebar コンポーネントを実装する
components/app-sidebar.tsx を作成します:
• "use client" でクライアントコンポーネントとして指定
• usePathname で現在のルートを取得
• navConfig をループしてメニュー項目をレンダリング
• ルートが一致したら isActive 属性を設定してハイライト - 6
ステップ6: 権限制御を追加する(任意)
RBAC による権限フィルタを実装します:
• NavItem インターフェースに roles フィールドを追加
• AppSidebar 内で useAuth からユーザーの役割を取得
• filter メソッドでメニュー項目を絞り込み
roles フィールドがないメニューは、デフォルトで全ユーザーに表示されます。
FAQ
shadcn/ui Sidebar と Ant Design のサイドバーは何が違いますか?
SidebarProvider は Root Layout と Dashboard Layout のどちらに置くべきですか?
モバイルで Sidebar を自動的に閉じるにはどうすればいいですか?
```tsx
const { setOpenMobile } = useSidebar();
<SidebarMenuButton onClick={() => setOpenMobile(false)}>
```
こうするとメニューをタップした後にドロワーが自動的に閉じます。
Sidebar の幅をカスタマイズするには?
1. CSS 変数を使う(おすすめ):
```tsx
<Sidebar style={{ "--sidebar-width": "280px" }} />
```
2. sidebar.tsx の SIDEBAR_WIDTH 定数を変更する
CSS 変数のほうが柔軟で、Sidebar ごとに異なる幅を設定できます。
多階層メニューはどう実装しますか?
• CollapsibleTrigger に 1 階層目のメニューボタンを入れる
• CollapsibleContent に SidebarMenuSub と 2 階層目のメニュー項目を入れる
• ChevronDown アイコンで開閉状態を示す
完全なコードは本文 3.5 節をご覧ください。
shadcn/ui Sidebar のアクセシビリティはどうですか?
4分で読めます · 公開日: 2026年3月27日 · 更新日: 2026年6月8日
Tailwind と shadcn/ui 実践ガイド
検索からこのページに来た場合は、前後の記事もあわせて読むと同じテーマの理解がかなり早く深まります。
前の記事
shadcn/ui のインストールとテーマカスタマイズ完全ガイド(CSS 変数つき)
shadcn/ui のインストール設定とテーマカスタマイズ手法を徹底解説。CSS 変数、OKLCH カラー、ダークモード切り替えまで網羅。ブランド化 UI デザインのベストプラクティスを 5 分で習得
第 2 / 11 記事
次の記事
Tailwind レスポンシブレイアウト実践:コンテナクエリとブレークポイント戦略
Tailwind CSS のコンテナクエリとブレークポイント戦略を詳しく解説。ビューポートからコンテナへのレスポンシブ設計の進化を理解し、コンポーネント単位のレスポンシブレイアウトを実現しましょう。
第 4 / 11 記事
関連記事
Tailwind v4 + Vite:5 分で完成する設定テンプレートとディレクトリ構成
Tailwind v4 + Vite:5 分で完成する設定テンプレートとディレクトリ構成
Tailwind ダークモード:class と data-theme の2つの方式を比較
Tailwind ダークモード:class と data-theme の2つの方式を比較
shadcn/ui コンポーネント組み合わせパターン:実践ベストプラクティス
コメント
GitHubアカウントでログインしてコメントできます