巷で噂のshadcn/uiをNext.jsで使ってみた

# shadcn/uiとは

shadcn/uiとは、これは [Radix UI](https://www.radix-ui.com/)と[Tailwind CSS](https://tailwindcss.com/)を使って書かれた UI コンポーネントをまとめたもので、TailwindCSS を通じてスタイルをカスタマイズできる。[2023 JavaScript Rising Stars](https://risingstars.js.org/2023/en#section-all)では、全Projectで見事ランキング1位に輝いた!!

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

:::note warn
最新のバージョンの**shadcn/ui**のインストール方法は以下のサイトで解説しております。(React 19・Next.js 15にも対応)
:::

https://pathy.jp/posts/shadcn

# インストール

この記事では、Next.jsの場合を紹介する。Viteなど他のフレームワークのインストール方法は[Installation](https://ui.shadcn.com/docs/installation)を参照。

まず、 Next.jsをインストールしていない人はインストールしてください。

```shell-session
# npx create-next-app@latest my-app --tailwind --eslint
Need to install the following packages:
create-next-app@14.1.0
Ok to proceed? (y) y
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
Creating a new Next.js app in /workspaces/shadcn/my-app.
```

プロジェクトディレクトリに移行。

```
$ cd my-app
```

以下コマンドでshadcnのセットアップができます。

```shell-session:my-app/
$ npx shadcn-ui@latest init
```

initすると以下のような質問をされ、`component.json`ができる。

```
1. Would you like to use TypeScript (recommended)? no/yes
TypeScriptを使いたいか？

2. Which style would you like to use? › Default
デフォルトかNew Yorkどちらのスタイルを使いたいか？

3. Which color would you like to use as base color? › Slate
ベースカラーは何にするか？(後から変更不可)

4. Where is your global CSS file? › › app/globals.css
グローバルCSSファイルはどこに置くか?

5. Do you want to use CSS variables for colors? › no / yes
CSS変数で色を設定するか?(後から変更不可)

6. Where is your tailwind.config.js located? › tailwind.config.js
tailwind.config.jsをどこに置くか？

7. Configure the import alias for components: › @/components
コンポーネントをインポートのエイリアスは？

8. Configure the import alias for utils: › @/lib/utils
utilsのimportのエイリアスは？

9. Are you using React Server Components? › no / yes
React Serverのコンポーネントを使うか?
```

:::note
2と3のスタイルとベースカラーの組み合わせはhttps://ui.shadcn.com/themes で確認できる。
:::

`my-app/src/app/page.js`を以下のようにする。

:::note warn
shadcn/uiは推奨TypeScriptだが、この記事ではJavaScriptで行う。
:::


```jsx:my-app/src/app/page.js
export default function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <div>
        <button>クリック！</button>
      </div>
    </main>
  );
}
```


`npm run dev`を叩き、http://localhost:3000 にアクセスすると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/78e85456-ac7d-3f79-2917-e55ec496feb1.png)

のような画面になる。ここからカスタマイズしていく。

以下のコマンドをターミナルで叩くと、`my-app/src/components/ui/button.jsx`にボタンのコンポーネントが作成される。

```shell-session
$ npx shadcn-ui@latest add button
```

早速、追加したボタンのコンポーネントを使ってみる。

```diff_jsx:my-app/src/app/page.js
+ import { Button } from "@/components/ui/button";

export default function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
     <div>
-        <button>クリック！</button>
+        <Button>クリック</Button>
      </div>
    </main>
  );
}
```

すると、以下のようになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/0b22de0f-5bbd-72f2-a029-bb93b6ef2320.png)

以下のようにaddに引数をつけなかったら、インストールするコンポーネントを選択できる。

```shell-session
$ npx shadcn-ui@latest add
? Which components would you like to add? › Space to select. A to toggle all. Enter to submit. 
◯   accordion
◯   alert
◯   alert-dialog
◯   aspect-ratio
◯   avatar
◯   badge
◯   button
◯   calendar
◯   card
◯ ↓ carousel
```


diffコマンドを使うと、更新のあるコンポーネントを調べられる。

```shell-session
$ npx shadcn-ui diff
```

# テーマ

テーマの設定で **CSS変数** を使用するか、**Tailwind CSSユーティリティクラス** を使用するかを選択できる。

## CSS変数

**components.json**の`tailwind.cssVariables`を *true* にする。

```html
<div className="bg-background text-foreground" />
```

より詳細な設定は[Theming](https://ui.shadcn.com/docs/theming#css-variables)を参照。

## ユーティリティクラス

**components.json**の`tailwind.cssVariables`を *false* にする。

```html
<div className="bg-zinc-950 dark:bg-white" />
```

# ダークテーマ

インストールする。

```
npm install next-themes
```

`my-app/src/components/theme-provider.jsx`が作成されるので、`my-app/src/app/layout.js`にimportして、以下のように編集する。

```diff_jsx
import { Inter } from "next/font/google";
import "./globals.css";
+ import { ThemeProvider } from "@/components/theme-provider";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({ children }) {
  return (
    <html lang="jp">
      <body className={inter.className}>
+        <ThemeProvider
+          attribute="class"
+          defaultTheme="dark"
+          enableSystem
+          disableTransitionOnChange
+        >
          {children}
+        </ThemeProvider>
      </body>
    </html>
  );
}

```

再度、http://localhost:3000 にアクセスするとダークモードになっている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/78fda8dc-8201-f56b-6f4a-eae04f04df7e.png)

# Figma

<iframe style="border: 1px solid rgba(0, 0, 0, 0.1);" width="800" height="450" src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FEFGF1GcGXKUfQDHXfJrc1Z%2F%2540shadcn%252Fui---Design-System-(Community)%3Ftype%3Ddesign%26node-id%3D13%253A2144%26mode%3Ddesign%26t%3D4xc4B6I53pBlq6Z8-1" allowfullscreen></iframe>

Figmaに多くのコンポーネントがあるので、以下URLからコピーして持ってくることができる。

https://www.figma.com/community/file/1203061493325953101

# Components

以下にbutton以外の多くのコンポーネントが掲載されている。

https://ui.shadcn.com/docs/components/accordion
 
# shadcn/uiのアーキテクチャ

shadcn/uiのアーキテクチャについて以下に書かれていた。

https://manupa.dev/blog/anatomy-of-shadcn-ui

上記の日本語の解説 → [shadcn/ui の内部構造を探る](https://zenn.dev/morinokami/articles/anatomy-of-shadcn-ui)


# 参考文献

* [2023 年の JavaScript の新星](https://risingstars.js.org/2023/en#section-all)
* [The anatomy of shadcn/ui](https://manupa.dev/blog/anatomy-of-shadcn-ui)
* [shadcn/uiライブラリを使いこなすための基礎 | アールエフェクト](https://reffect.co.jp/react/shadcn-react#shadcnui)