Next.js 13によるモーダルウィンドウ実装の奨め
本記事の完成品です。
はじめに
今回は、Next.js 13 を使ったモーダルウィンドウの実装について解説します。この記事は、Web 開発において頻出するモーダルウィンドウの作成が初めての方、または実装方法をさらに簡単にしたいと考えている方に特にお勧めです。
本記事では、具体的なコード例と共にステップバイステップで進めていきますので、初心者の方でも安心して読み進められます。では、さっそく始めていきましょう。
モーダルウィンドウとは
既にご存知の方も多いと思いますが、モーダルウィンドウとは、Web サイトやアプリケーションの画面上に表示されるポップアップウィンドウのことです。モーダルウィンドウは、ユーザーの操作を妨げることなく、画面上に情報を表示することができるため、Web サイトやアプリケーションのユーザーインターフェースにおいて頻繁に利用されています。
ダイアログボックスやアラート、ポップアップウィンドウなど、様々な名称で呼ばれることがありますが、本記事ではモーダルウィンドウと統一して記述していきます。
実装
それでは、実際にモーダルウィンドウを実装していきましょう。
shadcn/ui のインストール
今回スタイルは、shadcn/uiを利用します。shadcn/ui は、Radix UI と Tailwind CSS を使用して構築された再利用可能なコンポーネントです。
新しいプロジェクトの依存関係を初期化するには、init コマンドを使用します。
pnpx shadcn-ui init
init コマンドは、依存関係をインストールし、cn util を追加し、tailwind.config.js を設定し、プロジェクト用の CSS 変数を設定します。
次に add コマンドでコンポーネントをプロジェクトに追加し、今回利用するモーダルウィンドウをインストールします。
pnpx shadcn-ui add dialog
ディレクトリ構成
今回は認証系のモーダルウィンドウを実装するため、AuthModal
を作成する例を紹介します。
ディレクトリ構成は以下のようになります。
components
Modal.tsx
の実装は以下のようになります。
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
interface ModalProps {
isOpen: boolean;
onChange: (open: boolean) => void;
title: string;
description: string;
children: React.ReactNode;
}
const Modal: React.FC<ModalProps> = ({ isOpen, onChange, title, description, children }) => {
return (
<Dialog open={isOpen} defaultOpen={isOpen} onOpenChange={onChange}>
<DialogContent>
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
<DialogDescription>{description}</DialogDescription>
</DialogHeader>
{children}
</DialogContent>
</Dialog>
);
};
export default Modal;
この Modal コンポーネントを利用して、AuthModal.tsx
を作成します。
'use client';
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import useAuthModal from '@/hooks/useAuthModal';
import Modal from './Modal';
const AuthModal = () => {
const router = useRouter();
const { onClose, isOpen } = useAuthModal();
return (
<Modal
title="Title"
description="lorem ipsum dolor sit amet, consectetur adipiscing elit."
isOpen={isOpen}
onChange={onChange}
>
<div className="flex flex-col space-y-4">
<button className="btn btn-primary">Login with GitHub</button>
<button className="btn btn-secondary">Login with Google</button>
</div>
</Modal>
);
};
export default AuthModal;
今回は実装を行いませんが、AuthModal ではセッション情報を取得し、ログイン状態に応じて表示を切り替えることを想定しています。
hooks
useAuthModal.ts
の実装は以下のようになります。
import { create } from 'zustand';
interface AuthModalStore {
isOpen: boolean;
onOpen: () => void;
onClose: () => void;
}
const useAuthModal = create<AuthModalStore>((set) => ({
isOpen: false,
onOpen: () => set({ isOpen: true }),
onClose: () => set({ isOpen: false }),
}));
export default useAuthModal;
ここでは、zustand
のcreate
を利用して、isOpen
、onOpen
、onClose
の 3 つの状態を管理しています。
providers
アプリ全体で利用できるように、ModalProviders.tsx
を作成します。
'use client';
import { useEffect, useState } from 'react';
import AuthModal from '@/components/AuthModal';
const ModalProviders: React.FC = () => {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
if (!isMounted) {
return null;
}
return (
<>
<AuthModal />
</>
);
};
export default ModalProviders;
ここでのコードを解説します。
isMounted
は、useEffect
を利用して、初回レンダリング時にtrue
になります。isMounted
がfalse
の場合は、null
を返します。isMounted
がtrue
の場合は、AuthModal
を返します。
ここでの実装は、AuthModal
のみですが、アプリケーション全体で利用するモーダルウィンドウがある場合は、ここで管理することをおすすめします。
Layout
最後に、Layout.tsx
でModalProviders
を読み込みます。
import { Inter } from 'next/font/google';
import ModalProviders from '@/providers/ModalProvider';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
export const 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={inter.className}>
<ModalProviders />
{children}
</body>
</html>
);
}
これで、モーダルウィンドウの実装は完了です。
モーダルウィンドウの表示
モーダルウィンドウを表示するには、useAuthModal
で定義したonOpen
を呼び出します。
今回のデモではHeader.tsx
でボタンを作成し、クリック時にonOpen
を呼び出します。
'use client';
import Link from 'next/link';
import { Button } from '@/components/ui/button';
import useAuthModal from '@/hooks/useAuthModal';
const Header = () => {
const { onOpen } = useAuthModal();
return (
<>
<div className="fixed top-0 left-0 right-0 z-50 bg-primary-foreground">
<div className="container flex justify-between items-center py-4 border-b border-b-white backdrop-blur-md">
<Link href="/">LOGO</Link>
<div className="flex gap-2 items-center">
<Button onClick={onOpen}>openModal</Button>
</div>
</div>
</div>
</>
);
};
export default Header;
これで、モーダルウィンドウが表示されるようになりました。
まとめ
今回は、Next.js でモーダルウィンドウを実装する方法を紹介しました。 モーダルウィンドウの実装は、アプリケーションによって異なるため、今回の実装をそのまま利用することはできませんが、モーダルウィンドウの実装に必要な要素を紹介できたと思います。