レビュー済み·難易度: 中級·更新: 2026-04-17

Next.js の Parallel Routes で複数スロットを同時表示する

@スロット記法を使い、同一ページに複数の独立したルートコンテンツを並列表示する実装例。

nextjsroutingui-component

対応バージョン

nextjs 15

前提環境

Next.js App Router のディレクトリ構成と Route Groups を理解していること

概要

Parallel Routes を使うと、同一の URL で複数の独立したページコンテンツを並列表示できる。 @slotName ディレクトリ配下に page.tsx を置き、親の layout.tsx でスロットとして受け取る。 ダッシュボードで複数のウィジェットを独立したセグメントとして管理するケースに向いている。

インストール

# 追加インストールは不要

ディレクトリ構成

src/app/dashboard/
├── layout.tsx          ← @analytics と @team を受け取る
├── page.tsx            → /dashboard のメインコンテンツ
├── @analytics/
│   ├── page.tsx        → analytics スロット(/dashboard でレンダリング)
│   └── default.tsx     ← スロットが一致しない場合のフォールバック
└── @team/
    ├── page.tsx        → team スロット(/dashboard でレンダリング)
    └── default.tsx

実装例

// src/app/dashboard/layout.tsx
type Props = {
  children: React.ReactNode;
  analytics: React.ReactNode; // @analytics スロット
  team: React.ReactNode;      // @team スロット
};

export default function DashboardLayout({ children, analytics, team }: Props) {
  return (
    <div className="p-6 space-y-6">
      {/* メインコンテンツ */}
      <section>{children}</section>

      {/* Parallel Routes のスロット */}
      <div className="grid grid-cols-2 gap-6">
        <div className="rounded border p-4">{analytics}</div>
        <div className="rounded border p-4">{team}</div>
      </div>
    </div>
  );
}
// src/app/dashboard/page.tsx
export default function DashboardPage() {
  return <h1 className="text-lg font-bold">ダッシュボード</h1>;
}
// src/app/dashboard/@analytics/page.tsx
export default function AnalyticsSlot() {
  return (
    <div>
      <h2 className="mb-2 text-sm font-medium text-gray-600">アナリティクス</h2>
      <p className="text-2xl font-bold">1,234</p>
      <p className="text-xs text-gray-400">先月比 +12%</p>
    </div>
  );
}
// src/app/dashboard/@team/page.tsx
export default function TeamSlot() {
  return (
    <div>
      <h2 className="mb-2 text-sm font-medium text-gray-600">チームメンバー</h2>
      <ul className="space-y-1 text-sm">
        <li>田中 太郎</li>
        <li>鈴木 花子</li>
      </ul>
    </div>
  );
}
// src/app/dashboard/@analytics/default.tsx(フォールバック)
export default function AnalyticsDefault() {
  return null;
}

ポイント

  • @slotName ディレクトリ名がスロット名になり、親 layout.tsx の props として受け取る
  • スロットは URL に影響しない(/dashboard のまま)
  • default.tsx を置かないとスロットが一致しない URL で 404 になる
  • 各スロットは独立してナビゲーションできるため、スロットごとに loading.tsx / error.tsx を配置できる
  • Route Groups と組み合わせてレイアウトをさらに細かく分けることも可能

注意点

@folder 記法でスロットを定義する。スロットは URL に影響しない。default.tsx を置かないと、スロットが一致しないときに 404 になる。ダッシュボードで複数のウィジェットを独立して表示するケースに向いている。

関連サンプル