【Next.js】layout.tsxで共通レイアウトを作る

JavaScript

こんにちは、かつコーチです。

前回はpage.tsxを使ったファイルベースルーティングの基本を解説し、フォルダを増やすだけでページが増えることを確認しました。

ページが増えてくると、今度は「どのページにも共通するヘッダーやフッターを、毎回コピペするのは面倒だ」という悩みが出てきます。

今回は、その悩みを解決してくれるlayout.tsxの使い方を詳しく見ていきましょう。

layout.tsxとは?

複数ページで共有される「土台」を定義するファイル

layout.tsxとは、同じフォルダ配下にある複数のページで共通して使われる、レイアウト(見た目の土台)を定義するファイルです。

create-next-app直後から存在するapp/layout.tsxは、ルートレイアウトと呼ばれ、サイト全体のすべてのページに適用される、最も外側のレイアウトです。

// app/layout.tsx
import type { Metadata } from "next";
import "./globals.css";

export const metadata: Metadata = {
  title: "かつコーチのNext.js入門",
  description: "初心者向けにNext.jsをやさしく解説します",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body>{children}</body>
    </html>
  );
}

なぜレイアウトを共通化する必要があるのか

前回作った/about/blog/newsのようなページに、それぞれ個別で<html>タグやヘッダーを書いていくのは非効率です。

さらに、サイト共通のヘッダーの文言を1箇所直すだけで、全ページに変更を反映したい、という場面もよくあります。

layout.tsxを使えば、こうした「共通部分」と「ページごとに変わる部分」を分離して管理できます。

Reactシリーズで、共通のヘッダー・フッターを<Layout>というコンポーネントで囲んで使い回すテクニックを紹介しましたが、Next.jsではその考え方がフレームワークの標準機能として組み込まれている、とイメージするとわかりやすいです。

基本の書き方・実装手順

手順1:childrenの役割を理解する

layout.tsxのポイントは、childrenというPropsです。

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body>{children}</body>
    </html>
  );
}

このchildrenの部分に、同じフォルダ配下にあるpage.tsxの中身が、自動的に差し込まれます。

つまり、/aboutにアクセスすると、RootLayoutchildren部分にapp/about/page.tsxの中身がはめ込まれた状態で表示される、という仕組みです。

手順2:ヘッダー・フッターを共通レイアウトに追加する

実際に、サイト全体で使うヘッダーとフッターをlayout.tsxに追加してみましょう。

// app/layout.tsx
import type { Metadata } from "next";
import "./globals.css";

export const metadata: Metadata = {
  title: "かつコーチのNext.js入門",
  description: "初心者向けにNext.jsをやさしく解説します",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body>
        <header>
          <p>かつコーチ | Next.js入門シリーズ</p>
        </header>

        {children}

        <footer>
          <p>&copy; 2026 かつコーチ</p>
        </footer>
      </body>
    </html>
  );
}

この状態で//aboutなど、どのページにアクセスしても、共通のヘッダーとフッターが表示されるようになります。

手順3:特定のフォルダだけに適用されるレイアウトを作る

layout.tsxapp直下だけでなく、任意のフォルダにも配置できます。

app/
├── layout.tsx          ← 全ページ共通
├── page.tsx
└── blog/
    ├── layout.tsx      ← blog配下のページだけに適用
    └── news/
        └── page.tsx
// app/blog/layout.tsx
export default function BlogLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div>
      <nav>
        <p>ブログ内メニュー</p>
      </nav>
      {children}
    </div>
  );
}

このように、フォルダごとにlayout.tsxを重ねて配置すると、ルートレイアウトの中に、さらにblog専用のレイアウトが入れ子になって適用されます。

「サイト全体で共通の部分」と「特定のセクションだけで共通の部分」を、フォルダの階層で自然に分けられるのが、この仕組みの強みです。

つまずきやすいポイント:私の実体験

childrenを書き忘れて画面が真っ白になった話

ここで、私が実際につまずいた経験を1つ共有します。

blog配下専用のヘッダーを追加しようとしてlayout.tsxを作ったとき、{children}を書き忘れたまま保存してしまい、/blog/newsにアクセスしても画面が真っ白になる、という状態にハマったことがあります。

❌ Before:childrenを書き忘れる

// app/blog/layout.tsx(バグあり)
export default function BlogLayout() {
  return (
    <div>
      <nav>
        <p>ブログ内メニュー</p>
      </nav>
    </div>
  );
}

このコードでは、childrenというPropsを受け取っておらず、当然JSXの中でも表示していません。

その結果、page.tsx側の中身がどこにも差し込まれず、ナビゲーションだけが表示されて肝心のページ内容が消えてしまっていました。

✅ After:childrenを正しく受け取り、表示する

// app/blog/layout.tsx(修正後)
export default function BlogLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div>
      <nav>
        <p>ブログ内メニュー</p>
      </nav>
      {children}
    </div>
  );
}

このときは、コンソールにエラーが出るわけでもなく、TypeScriptの型チェックも通ってしまっていたため、原因を見つけるのに少し時間がかかりました。

layout.tsxを作るときは、「childrenを受け取る」「JSXの中で必ず{children}を書く」の2点をセットで確認する、という習慣がついてからは、同じミスをしなくなりました。

まとめ

この記事のポイント

  • layout.tsxは、複数のページで共有されるレイアウト(土台)を定義するファイル
  • app直下のlayout.tsxはルートレイアウトと呼ばれ、サイト全体に適用される
  • childrenというPropsに、そのフォルダ配下のpage.tsxの中身が自動的に差し込まれる
  • フォルダごとにlayout.tsxを重ねて配置でき、特定のセクションだけの共通レイアウトも作れる
  • childrenを書き忘れると、ページの中身が表示されなくなるので注意する

次に読むべき記事

これで、Next.jsの入門・環境構築編の5本が完了しました。

次回からは一歩進んで、URLの一部を可変にする動的ルートや、フォルダをURLに影響させずにグループ化するルートグループなど、より実践的なルーティングの書き方を解説していきます。

→ 次の記事:ルートグループ・動的ルートの書き方

タイトルとURLをコピーしました