Next.jsのトップ画面をTailwind CSSとshadcnで素早く作る

2024/01/11に公開

はじめに

Next.jsで認証の仕組みを作っていくチュートリアルの具体的な作業に入っていきます。

今回のゴール

この記事のゴールはNext.jsが動かせる状態にして、トップ画面にタイトルとボタンを設置。
その後、ボタンをクリックするとログイン画面、アカウント登録画面に遷移するところまでとなります。

  • トップ画面完成イメージ

Image from Gyazo

  • ボタンをクリックするとログイン画面、アカウント登録画面に遷移

Image from Gyazo

Image from Gyazo

Next.jsで画面を作成したことがある方や、画面遷移の実装をしたことがある方は飛ばして頂いても問題ありません。

Tailwind CSSとは

このライブラリの特徴は、Bootstrapなどの他のCSSフレームワークと異なり、ボタンやテーブルなどの要素に対する一連の定義済みクラスを提供しないことである。代わりに、"ユーティリティ"CSSクラスを提供するので、これを組み合わせて要素をスタイリングする。

Image from Gyazo

引用元:https://ja.wikipedia.org/wiki/Tailwind_CSS

CSSを書いたことがある方ならイメージつくかと思いますが、CSSを書くよりは若干短縮してCSSっぽいものを定義することができます。

Next.jsの開発元であるVercelはTailwind CSSを推奨しておりこの後登場するNext.jsのセットアップ時に一緒にTailwind CSSを導入できるようになっています。

今回のチュートリアルでも使っていこうと思います。

shadcn/uiとは

shadcn/uiはReactのUI コンポーネントライブラリであるRadix UIとCSSフレームワークのTailwind CSS を利用して作成した再利用可能なコンポーネントを提供してくれるライブラリです。

この後、入力フォームを作成したり、ボタンを作成したり実装に必要なコンポーネントを作っていくのですが、さすがにdivタグやbuttonタグを駆使して1から作るとなると時間がかかります。

ライブラリを活用して実装時間を短縮していきたいと思います。

URL: https://ui.shadcn.com/

環境セットアップ

下記のコマンドでNext.jsバージョン14をセットアップしていきます。

$ npx create-next-app@14.0.4 tutorial-nextjs-14-auth

幾つか質問が出てきますが全てYesで問題ありません。
3番目に聞かれた質問が先ほど紹介したTailwind CSSとなります。
Yesを選択することですぐ使える状態となります。

Need to install the following packages:
create-next-app@14.0.4
Ok to proceed? (y) y
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … 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 /Users/test/Documents/workspace/tutorial-nextjs-14-auth.

Using npm.

Initializing project with template: app-tw


Installing dependencies:
- react
- react-dom
- next

Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- autoprefixer
- postcss
- tailwindcss
- eslint
- eslint-config-next

それでは一度、Next.jsを起動してみましょう。

$ npm run dev

localhost:3000で下記の画面が表示されればOKです。

Image from Gyazo

次にshadcnをインストールしていきます。

npx shadcn@latest init

ここでも幾つか質問が出てきます。
①Styleは? -> New York
②Base Colorは? -> slate
③CSS Valiablesは使う? -> true

こちらは後で設定変更も可能です。

✔ Preflight checks.
✔ Verifying framework. Found Next.js.
✔ Validating Tailwind CSS.
✔ Validating import alias.
✔ Which style would you like to use? › New York
✔ Which color would you like to use as the base color? › Slate
✔ Would you like to use CSS variables for theming? … no / yes
✔ Writing components.json.
✔ Checking registry.
✔ Updating tailwind.config.ts
✔ Updating app/globals.css
✔ Installing dependencies.
✔ Created 1 file:
  - lib/utils.ts

Success! Project initialization completed.
You may now add components.

インストールが完了すると幾つかファイルが追加されているかと思います。
先ほど設定した内容はこちらに反映されています。

components.json
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "app/globals.css",
    "baseColor": "slate",
    "cssVariables": true,
    "prefix": ""
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  }
}

また/lib配下に下記のファイルが作成されます。

utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

こちらはTailwind CSSを書くときの便利な関数となります。
使い方については後ほどご紹介します。

ここまではあくまでshadcnを使うための土台の設定みたいなもので、
個々のコンポーネントを使うにはそれぞれ都度インストールしていくことになります。

まずはボタンのコンポーネントをインストールしてみます。

$ npx shadcn@latest add button

すると、/components/ui配下に下記のファイルが作成されます。

button.tsx
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 transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
  {
    variants: {
      variant: {
        default:
          "bg-primary text-primary-foreground shadow hover:bg-primary/90",
        destructive:
          "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
        outline:
          "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
        secondary:
          "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default: "h-9 px-4 py-2",
        sm: "h-8 rounded-md px-3 text-xs",
        lg: "h-10 rounded-md px-8",
        icon: "h-9 w-9",
      },
    },
    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 }

最後にエクスポートされている、Button(必要に応じてbuttonVariants)を使ってボタンを実装していきます。

コードを読むと、variantsizeというキーがあるかと思います。
そしてそれぞれにTailwind CSSで色々と定義されています。
ボタンコンポーネントを扱うときにはこのvariantsizeを使うことでボタンの色や大きさを自分好みに設定できるようになっています。

トップ画面作成

まずボタンコンポーネントが使えるか確認したいので、/app配下のpage.tsxで下記のようにコードを書きます。

page.tsx
import { Button } from "@/components/ui/button"

export default function Home() {
  return (
    <main>
      <Button variant='destructive' size='lg'>テスト用のボタン</Button>
    </main>
  )
}

Next.jsを起動すると、赤いボタンが表示されるかと思います。

Image from Gyazo

今回はvariant='destructive'と設定したので赤になっていますが、他のvariantを使うと色が変わることが確認できるかと思います。

ボタンコンポーネントが使えることが確認できましたので、早速トップ画面を作っていきます。

globals.cssに以下のコードを追記します。shadcnのインストールで色々とコードが書き込まれていますがそのまま残しておいてください。

globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;

+ html,
+ body,
+ :root {
+   height: 100%;
+ }

以下、略

次にボタンコンポーネントに画面遷移の処理を実装したコンポーネントを作ります。

  • アカウント登録画面に遷移するコンポーネント
  • ログイン画面に遷移するコンポーネント

2つ作ります。

/components/auth配下

login-button.tsx
'use client'

import { useRouter } from 'next/navigation'
import { Button } from '../ui/button'

export const LoginButton = () => {
  const router = useRouter()
  const onClick = () => {
    router.push('/auth/login')
  }
  return (
    <Button onClick={onClick} className="w-full cursor-pointer">
      ログインする
    </Button>
  )
}

同じく/components/auth配下

register-button.tsx
'use client'

import { useRouter } from 'next/navigation'
import { Button } from '../ui/button'

export const RegisterButton = () => {
  const router = useRouter()
  const onClick = () => {
    router.push('/auth/register')
  }
  return (
    <Button
      onClick={onClick}
      variant="secondary"
      className="w-full cursor-pointer"
    >
      アカウントを登録する
    </Button>
  )
}

作成後に、トップ画面でこれらのコンポーネントを使います。

page.tsx
import { LoginButton } from '@/components/auth/login-button'
import { RegisterButton } from '@/components/auth/register-button'

export default function Home() {
  return (
    <main className="flex h-full flex-col items-center justify-center bg-sky-100">
      <div className="space-y-6 text-center">
        <h1 className={'text-6xl font-semibold drop-shadow-md'}>
          トップ画面
        </h1>
        <p className="text-lg">Next.jsによる認証チュートリアル</p>
        <div>
          <LoginButton />
        </div>
        <div>
          <RegisterButton />
        </div>
      </div>
    </main>
  )
}

Next.jsを起動し下記のような内容が表示されればOKです。

Image from Gyazo

補足:このような画面が出てくるケースがあるかと思います。
クライアントコンポーネントで動かす必要のあるケースで'use client'をつけ忘れた場合によく出てくるメッセージです。
今回のケースですと、login-button.tsxregister-button.tsxなどでつけ忘れていないかご確認ください。

Image from Gyazo

現状、ボタンをクリックすると「404 | This page could not be found.」が表示されるかと思います。

この記事の最後のセクションとなるログインとアカウント登録の画面を作成していきたいと思います。

ログインとアカウント登録の画面作成

  • ログイン画面

/app/auth/login配下に下記のファイルを作成します

page.tsx
const LoginPage = () => {
  return <div>ログイン画面</div>
}

export default LoginPage
  • アカウント登録画面

/app/auth/register配下に下記のファイルを作成します

page.tsx
const RegisterPage = () => {
  return <div>アカウント登録画面</div>
}

export default RegisterPage

トップ画面からそれぞれのページに遷移できればOKです。

Image from Gyazo

Image from Gyazo

まとめ

今回はNext.jsのセットアップ及びshadcnのセットアップを行いました。
その後、インストールしたライブラリを使ってトップ画面の作成と、ボタンをクリックして画面遷移の動作確認まで実施しました。

次回は再びこれらのライブラリを駆使してアカウント登録画面で使う入力フォームを作っていきます。
また作りながらTailwind CSSやshadcnの使い方をもう少し掘り下げていけたらと思います。

次の記事はこちら

https://shinagawa-web.com/blogs/nextjs-tailwind-shadcn-account-registration-form

記事に関するお問い合わせ📝

記事の内容に関するご質問、ご意見などは、下記よりお気軽にお問い合わせください。
ご質問フォームへ

技術支援などお仕事に関するお問い合わせ📄

技術支援やお仕事のご依頼に関するお問い合わせは、下記よりお気軽にお問い合わせください。
お問い合わせフォームへ