Tomoki Ota's Blog

article icon

Next.js 15でshadcn/uiを使ってみる

作成日 

はじめに

以前、Qiitaに投稿した巷で噂のshadcn/uiをNext.jsで使ってみたという記事は、多くの方に読んでいただきました。特にこの記事は現在も多くの方にご覧いただいており、大変うれしく思っています。

巷で噂のshadcn/uiをNext.jsで使ってみた - Qiitashadcn/uiとはshadcn/uiとは、これは Radix UIとTailwind CSSを使って書かれた UI コンポーネントをまとめたもので、TailwindCSS を通じてスタイルをカ…
favicon of https://qiita.com/twrcd1227/items/d4a67bb155503fde30f5qiita.com
ogp of https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-user-contents.imgix.net%2Fhttps%253A%252F%252Fcdn.qiita.com%252Fassets%252Fpublic%252Farticle-ogp-background-afbab5eb44e0b055cce1258705637a91.png%3Fixlib%3Drb-4.0.0%26w%3D1200%26blend64%3DaHR0cHM6Ly9xaWl0YS11c2VyLXByb2ZpbGUtaW1hZ2VzLmltZ2l4Lm5ldC9odHRwcyUzQSUyRiUyRnFpaXRhLWltYWdlLXN0b3JlLnMzLmFwLW5vcnRoZWFzdC0xLmFtYXpvbmF3cy5jb20lMkYwJTJGMTU2MDk2JTJGcHJvZmlsZS1pbWFnZXMlMkYxNzIyNzQ4MTE3P2l4bGliPXJiLTQuMC4wJmFyPTElM0ExJmZpdD1jcm9wJm1hc2s9ZWxsaXBzZSZmbT1wbmczMiZzPTkyODYwZWU0MmIzMDc2MzM5ZjU4OTViMzc5ZWJhNzc2%26blend-x%3D120%26blend-y%3D467%26blend-w%3D82%26blend-h%3D82%26blend-mode%3Dnormal%26s%3Dda35fe799e245360dcb816e168208af3?ixlib=rb-4.0.0&w=1200&fm=jpg&mark64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZ3PTk2MCZoPTMyNCZ0eHQ9JUU1JUI3JUI3JUUzJTgxJUE3JUU1JTk5JTgyJUUzJTgxJUFFc2hhZGNuJTJGdWklRTMlODIlOTJOZXh0LmpzJUUzJTgxJUE3JUU0JUJEJUJGJUUzJTgxJUEzJUUzJTgxJUE2JUUzJTgxJUJGJUUzJTgxJTlGJnR4dC1hbGlnbj1sZWZ0JTJDdG9wJnR4dC1jb2xvcj0lMjMxRTIxMjEmdHh0LWZvbnQ9SGlyYWdpbm8lMjBTYW5zJTIwVzYmdHh0LXNpemU9NTYmdHh0LXBhZD0wJnM9OWFlYzA3OGUxNWZhMDYzY2QyOWRlMThiZWUwZmIzMGI&mark-x=120&mark-y=112&blend64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZ3PTgzOCZoPTU4JnR4dD0lNDB0d3JjZDEyMjcmdHh0LWNvbG9yPSUyMzFFMjEyMSZ0eHQtZm9udD1IaXJhZ2lubyUyMFNhbnMlMjBXNiZ0eHQtc2l6ZT0zNiZ0eHQtcGFkPTAmcz04MmUyNjAyOGUyYjE3M2E0NGZkZWNjOGUwMDQ3ODMyNw&blend-x=242&blend-y=480&blend-w=838&blend-h=46&blend-fit=crop&blend-crop=left%2Cbottom&blend-mode=normal&s=ac1335e5c551a7be678ed826040da2f9

そこで今回は、最新のNext.js 15とReact 19に対応したshadcn/uiの使い方を改めて解説していきたいと思います。これから新しいプロジェクトで採用を検討している方や、既存のプロジェクトでのバージョンアップを検討している方のお役に立てれば幸いです。

shadcn/uiとは?

shadcn/uiBeautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.
favicon of https://ui.shadcn.comui.shadcn.com
ogp of https://ui.shadcn.com/og.jpg

Qiitaの記事にも書いているのですが、shadcn/uiとはまず何かを紹介したいと思います。shadcn/uiとは、 Radix UITailwind CSSを使って書かれた UI コンポーネントをまとめたもので、Tailwind CSS でスタイルをカスタマイズできます。

shadcn/uiは、柔軟性拡張性 が高く、必要なコンポーネントだけを選択し、自分でカスタマイズすることができます。また、通常のコンポーネントライブラリとは異なり、npmパッケージとして配布されていないので、npmの依存関係に影響しません。また、コンポーネントのコードはCLIでダウンロードすることができます。

環境

この記事では、Next.js 15, React 19で実際にshadcn/uiをインストールしていきます。執筆時点の shadcn/uiのバージョンは2.1.8です。また、記事内では、srcディレクトリ、App RouterでNext.jsを実行しておりますが、Pages Routerやsrcディレクトリを使わない場合、Next.js 15・React 19以前のバージョンでも同じようにインストールは可能です。

インストール

npx shadcn@latest initをターミナルで叩いてインストールします。

$ npx shadcn@latest init
Need to install the following packages:
[email protected]
Ok to proceed? (y) y
? Which style would you like to use?# New YorkかDefaultのどちらのスタイルにするか選択する
   New York
    Default
? Which color would you like to use as the base color?# ベースカラーを以下から選ぶ
   Neutral
    Gray
    Zinc
    Stone
    Slate
? Would you like to use CSS variables for theming? › no / yes
# Next.js 15, React19を使用している場合はさらに以下の質問があります。
? How would you like to proceed? › 以下どちらのオプションを使用してインストールするかを選択する
    Use --force # 依存関係の競合やエラーを無視して強制的にインストールする
   Use --legacy-peer-deps # 互換性を維持しながらインストールする

ちなみに、スタイルについては、 https://ui.shadcn.com/docs/components/accordion でコンポーネントごとに、defaultとNewYorkの例をみることができます。また、テーマについては、https://ui.shadcn.com/themes でプレビューを確認することができます。

初期化が完了すると、components.jsonsrc/lib/utils.ts が作成されます。

src/lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
 
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}
components.json
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "src/app/globals.css",
    "baseColor": "neutral",
    "cssVariables": true,
    "prefix": ""
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  },
  "iconLibrary": "lucide"
}

componentsを導入する

ここではNext.jsで試しに accordion をインストールする。

$ npx shadcn@latest add accordion
? How would you like to proceed? › 以下どちらのオプションを使用してインストールするかを選択する
   Use --force # 依存関係の競合やエラーを無視して強制的にインストールする
    Use --legacy-peer-deps # 互換性を維持しながらインストールする

すると、components/ui/accordion.tsx が作成されます。

accordion.tsx
components/ui/accordion.tsx
"use client"
 
import * as React from "react"
import * as AccordionPrimitive from "@radix-ui/react-accordion"
import { ChevronDown } from "lucide-react"
 
import { cn } from "@/lib/utils"
 
const Accordion = AccordionPrimitive.Root
 
const AccordionItem = React.forwardRef<
  React.ElementRef<typeof AccordionPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
  <AccordionPrimitive.Item
    ref={ref}
    className={cn("border-b", className)}
    {...props}
  />
))
AccordionItem.displayName = "AccordionItem"
 
const AccordionTrigger = React.forwardRef<
  React.ElementRef<typeof AccordionPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
  <AccordionPrimitive.Header className="flex">
    <AccordionPrimitive.Trigger
      ref={ref}
      className={cn(
        "flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline text-left [&[data-state=open]>svg]:rotate-180",
        className
      )}
      {...props}
    >
      {children}
      <ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
    </AccordionPrimitive.Trigger>
  </AccordionPrimitive.Header>
))
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
 
const AccordionContent = React.forwardRef<
  React.ElementRef<typeof AccordionPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
  <AccordionPrimitive.Content
    ref={ref}
    className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
    {...props}
  >
    <div className={cn("pb-4 pt-0", className)}>{children}</div>
  </AccordionPrimitive.Content>
))
AccordionContent.displayName = AccordionPrimitive.Content.displayName
 
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }

インストールしたAccordionを以下のようにpage.tsxからインポートします。

src/app/sample/page.tsx
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion";
 
export default function Page() {
  return (
    <Accordion type="single" collapsible>
      <AccordionItem value="item-1">
        <AccordionTrigger>ここをクリック!</AccordionTrigger>
        <AccordionContent>Hello!</AccordionContent>
      </AccordionItem>
    </Accordion>
  );
}

npm run devして、https://localhost:3000/sample にアクセスすると以下のように表示されます。

alt text

そのほかのコンポーネントも同様にインストール可能です。どのようなコンポーネントが存在するかは https://ui.shadcn.com/docs/components/accordion に詳細が全て載っています。

chartを導入する

Rechartという機能を使って、さまざまなグラフを簡単に導入することができます。どのようなグラフがあるかは、 https://ui.shadcn.com/charts で確認することができます。

chartを導入する場合は、package.jsonを以下を追記します。

package.json
"overrides": {
  "react-is": "^19.0.0"
}

npm install --legacy-peer-depsをして、あとは上記のcomponentsを導入する と同じくnpx shadcn@latest add chartをターミナルで叩けば使用可能です。

終わりに

他にもFigmaとの連携やCSS変数やユーティリティクラスの使い方、ダークテーマの使い方について知りたい方は、Qiitaの記事の巷で噂のshadcn/uiをNext.jsで使ってみたを参考にしてみてください。

巷で噂のshadcn/uiをNext.jsで使ってみた - Qiitashadcn/uiとはshadcn/uiとは、これは Radix UIとTailwind CSSを使って書かれた UI コンポーネントをまとめたもので、TailwindCSS を通じてスタイルをカ…
favicon of https://qiita.com/twrcd1227/items/d4a67bb155503fde30f5qiita.com
ogp of https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-user-contents.imgix.net%2Fhttps%253A%252F%252Fcdn.qiita.com%252Fassets%252Fpublic%252Farticle-ogp-background-afbab5eb44e0b055cce1258705637a91.png%3Fixlib%3Drb-4.0.0%26w%3D1200%26blend64%3DaHR0cHM6Ly9xaWl0YS11c2VyLXByb2ZpbGUtaW1hZ2VzLmltZ2l4Lm5ldC9odHRwcyUzQSUyRiUyRnFpaXRhLWltYWdlLXN0b3JlLnMzLmFwLW5vcnRoZWFzdC0xLmFtYXpvbmF3cy5jb20lMkYwJTJGMTU2MDk2JTJGcHJvZmlsZS1pbWFnZXMlMkYxNzIyNzQ4MTE3P2l4bGliPXJiLTQuMC4wJmFyPTElM0ExJmZpdD1jcm9wJm1hc2s9ZWxsaXBzZSZmbT1wbmczMiZzPTkyODYwZWU0MmIzMDc2MzM5ZjU4OTViMzc5ZWJhNzc2%26blend-x%3D120%26blend-y%3D467%26blend-w%3D82%26blend-h%3D82%26blend-mode%3Dnormal%26s%3Dda35fe799e245360dcb816e168208af3?ixlib=rb-4.0.0&w=1200&fm=jpg&mark64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZ3PTk2MCZoPTMyNCZ0eHQ9JUU1JUI3JUI3JUUzJTgxJUE3JUU1JTk5JTgyJUUzJTgxJUFFc2hhZGNuJTJGdWklRTMlODIlOTJOZXh0LmpzJUUzJTgxJUE3JUU0JUJEJUJGJUUzJTgxJUEzJUUzJTgxJUE2JUUzJTgxJUJGJUUzJTgxJTlGJnR4dC1hbGlnbj1sZWZ0JTJDdG9wJnR4dC1jb2xvcj0lMjMxRTIxMjEmdHh0LWZvbnQ9SGlyYWdpbm8lMjBTYW5zJTIwVzYmdHh0LXNpemU9NTYmdHh0LXBhZD0wJnM9OWFlYzA3OGUxNWZhMDYzY2QyOWRlMThiZWUwZmIzMGI&mark-x=120&mark-y=112&blend64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZ3PTgzOCZoPTU4JnR4dD0lNDB0d3JjZDEyMjcmdHh0LWNvbG9yPSUyMzFFMjEyMSZ0eHQtZm9udD1IaXJhZ2lubyUyMFNhbnMlMjBXNiZ0eHQtc2l6ZT0zNiZ0eHQtcGFkPTAmcz04MmUyNjAyOGUyYjE3M2E0NGZkZWNjOGUwMDQ3ODMyNw&blend-x=242&blend-y=480&blend-w=838&blend-h=46&blend-fit=crop&blend-crop=left%2Cbottom&blend-mode=normal&s=ac1335e5c551a7be678ed826040da2f9
この記事をシェアするx icon
アイコン画像
Tomoki Ota

フルスタックエンジニア。Goが好き。趣味はカメラと旅行です📷