Пошук уроків, статей та іншого контенту
Створіть кореневий layout у Next.js та налаштуйте спільні метадані, шрифти й оболонку застосунку.
У Next.js з App Router кореневий layout — це файл app/layout.tsx, який обгортає всі сторінки застосунку.
Він використовується для:
спільної HTML-структури;
налаштування мови документа;
підключення глобальних стилів;
спільних метаданих;
підключення шрифтів;
створення загальної оболонки застосунку: шапки, основного контейнера та інших спільних елементів.
Кореневий layout є обов’язковим для застосунку з App Router. Він повинен містити теги <html> і <body>.
Мінімальний кореневий layout може виглядати так:
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="uk">
<body>{children}</body>
</html>
);
}Параметр children — це поточний вміст сторінки або вкладеного layout.
Наприклад, якщо застосунок має сторінку app/page.tsx, її вміст буде передано в children кореневого layout.
Замість того щоб додавати однакову структуру на кожну сторінку, її можна розмістити в кореневому layout:
import type { ReactNode } from "react";
export default function RootLayout({
children,
}: {
children: ReactNode;
}) {
return (
<html lang="uk">
<body>
<header>
<strong>Мій застосунок</strong>
</header>
<main>{children}</main>
<footer>
<small>© 2026 Мій застосунок</small>
</footer>
</body>
</html>
);
}Тепер header і footer будуть спільними для всіх сторінок, які використовують цей layout.
Метадані описують сторінку для браузера та пошукових систем. Наприклад:
заголовок вкладки браузера;
опис сторінки;
значення за замовчуванням для заголовків.
У кореневому layout метадані задаються через експорт змінної metadata:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Мій застосунок",
description: "Навчальний застосунок на Next.js",
};Next.js автоматично використовує ці значення під час формування HTML-документа. Додавати вручну тег <title> у layout не потрібно.
Для сторінок із різними назвами зручно визначити шаблон:
export const metadata: Metadata = {
title: {
default: "Мій застосунок",
template: "%s | Мій застосунок",
},
description: "Навчальний застосунок на Next.js",
};Тоді сторінка може експортувати власний заголовок:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Профіль",
};У браузері такий заголовок буде відображено як:
Профіль | Мій застосунокdefault використовується тоді, коли сторінка не має власного заголовка.
Next.js має вбудований механізм next/font, який допомагає підключати шрифти на етапі збирання застосунку.
Для шрифту Google використовується імпорт із next/font/google:
import { Inter } from "next/font/google";
const inter = Inter({
subsets: ["cyrillic", "latin"],
});Функція Inter повертає об’єкт із CSS-класом. Його потрібно додати до body:
<body className={inter.className}>{children}</body>Так шрифт застосовується до всього застосунку.
Створімо кореневий layout із:
українською мовою документа;
метаданими;
шрифтом Inter;
спільною шапкою;
основним вмістом;
підвалом;
глобальними стилями.
app/layout.tsximport type { Metadata } from "next";
import type { ReactNode } from "react";
import { Inter } from "next/font/google";
import "./globals.css";
const inter = Inter({
subsets: ["cyrillic", "latin"],
});
export const metadata: Metadata = {
title: {
default: "Мій застосунок",
template: "%s | Мій застосунок",
},
description: "Навчальний застосунок на Next.js",
};
export default function RootLayout({
children,
}: {
children: ReactNode;
}) {
return (
<html lang="uk">
<body className={inter.className}>
<div className="appShell">
<header className="header">
<strong>Мій застосунок</strong>
</header>
<main className="main">{children}</main>
<footer className="footer">
<small>© 2026 Мій застосунок</small>
</footer>
</div>
</body>
</html>
);
}app/page.tsximport type { Metadata } from "next";
export const metadata: Metadata = {
title: "Головна",
};
export default function HomePage() {
return (
<section>
<h1>Вітаємо!</h1>
<p>Це головна сторінка застосунку.</p>
</section>
);
}app/globals.css* {
box-sizing: border-box;
}
html,
body {
margin: 0;
min-height: 100%;
}
body {
background: #f4f4f5;
color: #18181b;
}
.appShell {
display: flex;
min-height: 100vh;
flex-direction: column;
}
.header,
.footer {
padding: 1rem 2rem;
background: #18181b;
color: white;
}
.main {
width: min(100% - 2rem, 960px);
flex: 1;
margin: 0 auto;
padding: 3rem 0;
}У цьому прикладі:
app/layout.tsx є кореневим layout;
lang="uk" задає мову HTML-документа;
metadata задає спільні метадані;
title.template формує заголовки сторінок;
Inter підключається до всього документа;
children містить вміст поточної сторінки;
header, main і footer утворюють спільну оболонку;
globals.css підключається один раз у кореневому layout.
childrenРозгляньмо спрощену структуру:
app/
├── layout.tsx
├── page.tsx
└── profile/
└── page.tsxКореневий layout обгортає і головну сторінку, і сторінку профілю:
<html>
<body>
<header>...</header>
<main>
Вміст поточної сторінки
</main>
<footer>...</footer>
</body>
</html>Для app/page.tsx у children буде вміст головної сторінки.
Для app/profile/page.tsx у children буде вміст сторінки профілю.
Сам layout не потрібно дублювати в окремих файлах сторінок.
<html> і <body>Ці теги визначають структуру всього HTML-документа:
<html lang="uk">
<body>{children}</body>
</html>Не варто замінювати їх звичайним контейнером div.
Файл глобальних стилів можна імпортувати в кореневому layout:
import "./globals.css";Це дає змогу застосовувати стилі до всього застосунку.
Кореневий layout призначений для спільної структури. Вміст конкретних сторінок потрібно розміщувати у файлах page.tsx.
Наприклад:
назва застосунку та footer — у layout.tsx;
заголовок сторінки профілю — у profile/page.tsx;
список товарів — у products/page.tsx.
<html> або <body>Неповний layout:
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return <main>{children}</main>;
}Кореневий layout повинен явно містити <html> і <body>:
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="uk">
<body>{children}</body>
</html>
);
}<head>Для стандартних метаданих не потрібно писати:
<head>
<title>Мій застосунок</title>
</head>Використовуйте типізований експорт:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Мій застосунок",
};Самого імпорту недостатньо:
const inter = Inter({
subsets: ["cyrillic", "latin"],
});Клас шрифту потрібно додати до елемента:
<body className={inter.className}>{children}</body>{children}Якщо не вставити children у layout, сторінки не матимуть місця для відображення:
<main>{children}</main>Без цього спільна оболонка може відображатися, але вміст сторінки — ні.
Для українського застосунку варто вказати:
<html lang="uk">Це допомагає браузерам та іншим інструментам правильно визначати мову вмісту.
Кореневий layout розташований у файлі app/layout.tsx.
Він обгортає всі сторінки застосунку.
Кореневий layout повинен містити <html> і <body>.
Вміст поточної сторінки передається через children.
Спільні метадані задаються через export const metadata.
Для заголовків сторінок можна використовувати title.template.
Шрифти підключаються через next/font і застосовуються через CSS-клас.
У layout зручно розміщувати спільну оболонку: шапку, основний контейнер і підвал.
Глобальні стилі можна імпортувати в кореневому layout.