Shadcn UI
Shadcn UIはRadix UIとTailwind CSSを用いたコンポーネントをプロジェクトに導入してくれるツールです。
ライブラリではなくツールとして活用できるのでプロジェクトと依存関係にはならず、作成したコンポーネントに関するあれこれをすべて手元の環境で行うところに利点があります。
このツールはNextjsやVite、RemixにAstroなど様々なプロジェクトで活用できます。
最近ではVercelが開発するAIがコンポーネントを生成してくれるv0.devの生成結果としても活用されています。
この記事ではNextjsを使う前提で記述しますが、本質的な部分は変わりません。
導入
Nextjsでプロジェクトを開始して、コンポーネントを作成します。
まずはnpx create-next-app
でアプリケーションの準備を行います。実行後の質問は以下のように答えました。Nextjsのバージョンは14.0.3です。
そして、npx shadcn-ui@latest init
でShadcn UIの初期化を行います。
基本的には全部デフォルトで答えましたが、global CSSの場所をsrc/app/globals.css
に、Tailwind CSSの設定ファイルの拡張子をtsに変更しました。
これによってtailwind.config.ts
、package.json
、package.lock.json
、src/app/globals.css
の更新が行われ、components.json
、src/lib/utils.ts
が作成されます。
tailwind.config.ts
はJavaScriptでCommon JSの記法に書き直されます。そして、contentで記述される内容も少し雑に書き換えられるので修正するのが良いと考えています。他の変更は今後作るUIのため設定を行ってます。
package.json
、package-lock.json
では生成するUIで利用するパッケージの準備をします。clsx
やtailwind-merge
などが利用されます。
src/app/globals.css
では生成するコンポーネントの色や角丸などのデザイントークンを生成されます。自由にカスタマイズして開発内容にあった内容に調整しましょう。
components.json
はShadcn UIに関する設定が詰め込まれています。プロジェクト中で唯一Shadcn UIに関連するファイルとなります。このファイルが他と依存関係を結ぶことはないのでShadcn UIを利用しなくなったときはこのファイルを削除するだけで脱却できます。
src/lib/utils.ts
はクラス名をつけるにあたって便利な関数を提供してくれます。clsx
とtailwind-merge
をいい感じに使えるようにしてくれています。
次にsrc/app/layout.tsx
とtailwind.config.ts
を触ってフォントの設定とShadcn UIのデフォルトのレイアウト設定を行います。
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
import { cn } from '@/lib/utils'
const inter = Inter({
subsets: ['latin'],
variable: "--font-sans"
})
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={cn(
"min-h-screen bg-background font-sans antialiased",
inter.variable
)}>{children}</body>
</html>
)
}
フォントのvariables
化とsrc/lib/utils.ts
に追加されたcn
を用いて基本的なスタイルを追加しています。
const { fontFamily } = require("tailwindcss/defaultTheme")
/** @type {import('tailwindcss').Config} */
module.exports = {
// ...
theme: {
extend: {
fontFamily: {
sans: ["var(--font-sans)", ...fontFamily.sans],
},
},
},
// ...
}
tailwindの方にもフォントの設定を反映します。
これで環境の準備は完了です。npx shadcn-ui@latest add button
のように実行することでボタンコンポーネントをsrc/components/ui
に生成してくれます(CLIを用いない場合でも公式サイトで対象のコンポーネントのコードをコピーして利用できます)。
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 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-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 hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }
Nextjsの命名に則ってkebab-caseでファイルを作ってくれます。スタイリングはTailwind CSSをベースにclass-variance-authority
で変数ごとに出し分けしながら定義しています。そして、Radix UIのSlot
を用いてasChild
を渡したときは要素をchildren
に合わせるようなコンポーネントを定義しています。
設定ファイル
設定ファイルは初期化によって生成されたcomponents.json
を指します。このファイルはCLIを用いたコンポーネント生成の際に用いられるファイルです。設定ファイルのJSON Schemaは公式から提供されています。
スタイリングのベースとなる設定を行ったり、tailwind
の設定ファイルを参照させたり、RSC・TSXの有無を設定したり、コンポーネントや便利関数をまとめるファイルの保存先を設定したりします。
基本的には初期化時に聞かれる内容が記述されているだけなので触ることはあまりないかもしれません。
おわりに
Shadcn UIを紹介しました。多くのUIコンポーネントライブラリは利用するアプリケーションがそれ自体に依存してしまい移行などがネックとなってしまいます。Shadcn UIではこの点を払拭して安定したコンポーネント開発が行えるのでぜひ試してみてはいかがでしょうか。