CreateLife ~AlwaysLatest~

【Next.js】shadcn/uiを使ってオシャレなアプリを爆速で作る

Next.js

shadcn/uiとは、カスタマイズ性に優れたUIコンポーネントの集まりです。
特筆すべきはコンポーネントライブラリではない点です。
従来のコンポーネントライブラリは概ね npmパッケージ として配布されておりそこで管理されますが、shadcn/uiはnpmの依存関係に影響しません。その代わりCLIを通してプロジェクトに直にコンポーネント(コード)を配置する仕組みをとります。
実際に使ってみましょう。

目次

  1. プロジェクトの作成
  2. shadcn/uiを初期化
  3. コンポーネントを追加する
  4. 任意のページにインポートする
  5. まとめ

1. プロジェクトの作成

npx create-next-app@latest my-app --typescript --tailwind --eslint

2. shadcn/uiを初期化

npx shadcn-ui@latest init
# ↓以下の質問に答えていく
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Do you want to use CSS variables for colors? › yes

ルートディレクトリ配下にcomponentsディレクトリが作成される

3. コンポーネントを追加する

使いたいコンポーネントを選択してCLI経由で追加します。試しにCardを使ってみます。

npx shadcn-ui@latest add card

先ほど作成されたcomponentsディレクトリにcard.tsxが追加されました。

中身は以下の通り(公式にあります)

import * as React from "react"

import { cn } from "@/lib/utils"

const Card = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn(
      "rounded-lg border bg-card text-card-foreground shadow-sm",
      className
    )}
    {...props}
  />
))
Card.displayName = "Card"

const CardHeader = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("flex flex-col space-y-1.5 p-6", className)}
    {...props}
  />
))
CardHeader.displayName = "CardHeader"

const CardTitle = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
  <h3
    ref={ref}
    className={cn(
      "text-2xl font-semibold leading-none tracking-tight",
      className
    )}
    {...props}
  />
))
CardTitle.displayName = "CardTitle"

const CardDescription = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
  <p
    ref={ref}
    className={cn("text-sm text-muted-foreground", className)}
    {...props}
  />
))
CardDescription.displayName = "CardDescription"

const CardContent = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"

const CardFooter = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("flex items-center p-6 pt-0", className)}
    {...props}
  />
))
CardFooter.displayName = "CardFooter"

export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }

4. 任意のページにインポートする

# page.tsx
import Image from "next/image";
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"


export default function Home() {
  return (
    <main className="grid lg:grid-cols-3 px-4 py-4 gap-4">
      <Card>
        <CardHeader>
          <CardTitle>Card Title</CardTitle>
          <CardDescription>Card Description</CardDescription>
        </CardHeader>
        <CardContent>
          <p>Card Content</p>
        </CardContent>
        <CardFooter>
          <p>Card Footer</p>
        </CardFooter>
      </Card>

    </main>
  );
}

実際の見た目

5. まとめ

デザインセンスが皆無の筆者はいつもUIをどうしようか迷います。tailwindのコンポーネントライブラリは色々ありますが、それぞれドキュメントを読んで、使い方を把握して、、みたいな事をやるのですが、このshadcn/uiに関してはもっとシンプルに使えそうな感覚でした。
柔軟な分、プロジェクトとしての管理を堅牢にしていかないとごちゃる可能性もあるかと思いましたが、サクッと作るには十分でした。いろいろ使ってみよう。