Пошук уроків, статей та іншого контенту
Винесіть навігацію, шапку, підвал та інші елементи, які спільно використовуються на сторінках.
У застосунку зазвичай є елементи, які потрібні на багатьох або на всіх сторінках:
шапка сайту;
логотип;
основна навігація;
підвал;
кнопка входу;
бічна панель.
Не варто копіювати однакову розмітку в кожну сторінку. У Next.js спільний інтерфейс можна винести в окремі компоненти та підключити їх у layout.tsx.
Layout — це обгортка для сторінок. Він отримує вміст поточної сторінки через проп children.
Для прикладу використаємо App Router:
app/
about/
page.tsx
layout.tsx
page.tsx
components/
Footer.tsx
Header.tsx
Navigation.tsxapp/layout.tsx — спільний layout для всього застосунку;
components/Header.tsx — шапка;
components/Navigation.tsx — навігація;
components/Footer.tsx — підвал;
app/page.tsx — головна сторінка;
app/about/page.tsx — сторінка «Про нас».
Для переходів між сторінками Next.js рекомендує використовувати компонент Link. Він дає змогу переходити між сторінками без повного перезавантаження браузера.
// components/Navigation.tsx
import Link from "next/link";
export default function Navigation() {
return (
<nav aria-label="Основна навігація">
<ul>
<li>
<Link href="/">Головна</Link>
</li>
<li>
<Link href="/about">Про нас</Link>
</li>
</ul>
</nav>
);
}href="/" веде на головну сторінку, а href="/about" — на сторінку за адресою /about.
Шапка використовує компонент навігації:
// components/Header.tsx
import Link from "next/link";
import Navigation from "./Navigation";
export default function Header() {
return (
<header>
<Link href="/" aria-label="Перейти на головну сторінку">
Мій сайт
</Link>
<Navigation />
</header>
);
}Компонент Header відповідає лише за шапку. Він не повинен містити розмітку всього документа або вміст окремої сторінки.
// components/Footer.tsx
export default function Footer() {
return (
<footer>
<p>© 2026 Мій сайт</p>
</footer>
);
}Тепер шапку, навігацію та підвал можна повторно використовувати в layout або інших компонентах.
Файл app/layout.tsx є кореневим layout для сторінок усередині папки app.
// app/layout.tsx
import type { Metadata } from "next";
import Footer from "../components/Footer";
import Header from "../components/Header";
import "./globals.css";
export const metadata: Metadata = {
title: "Мій сайт",
description: "Навчальний сайт на Next.js",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="uk">
<body>
<Header />
<main>{children}</main>
<Footer />
</body>
</html>
);
}childrenПараметр children містить сторінку, яка зараз відкривається.
Наприклад, для маршруту /about:
<Header />
<main>
сторінка app/about/page.tsx
</main>
<Footer />Тому всі сторінки автоматично отримують однакові шапку та підвал.
Кореневий layout також повинен містити:
<html>;
<body>;
children.
Головна сторінка може бути простою:
// app/page.tsx
export default function HomePage() {
return (
<section>
<h1>Головна сторінка</h1>
<p>Ласкаво просимо на наш сайт.</p>
</section>
);
}Сторінка «Про нас»:
// app/about/page.tsx
export default function AboutPage() {
return (
<section>
<h1>Про нас</h1>
<p>Це сторінка з інформацією про наш сайт.</p>
</section>
);
}Обидві сторінки не містять Header або Footer. Next.js додасть їх через app/layout.tsx.
Для базового прикладу можна додати стилі в app/globals.css:
/* app/globals.css */
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
color: #222;
}
header,
footer {
padding: 20px;
background-color: #f1f1f1;
}
header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
}
header a {
color: inherit;
text-decoration: none;
}
nav ul {
display: flex;
gap: 16px;
margin: 0;
padding: 0;
list-style: none;
}
main {
min-height: 70vh;
padding: 32px 20px;
}
footer {
text-align: center;
}Оскільки globals.css імпортується в кореневому layout, стилі доступні для всього застосунку.
Іноді різні частини сайту мають різний спільний інтерфейс. Наприклад, сторінки особистого кабінету можуть мати власну бічну панель.
Для цього створюють layout усередині відповідної папки:
app/
dashboard/
layout.tsx
page.tsx
settings/
page.tsx// app/dashboard/layout.tsx
export default function DashboardLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<section>
<aside>
<nav aria-label="Навігація кабінету">
<ul>
<li>
<a href="/dashboard">Огляд</a>
</li>
<li>
<a href="/dashboard/settings">Налаштування</a>
</li>
</ul>
</nav>
</aside>
<div>{children}</div>
</section>
);
}Для сторінки /dashboard/settings будуть використані обидва layout:
app/layout.tsx;
app/dashboard/layout.tsx.
У результаті сторінка отримає загальну шапку та підвал, а також бічну панель кабінету.
Для навігації між сторінками Next.js краще використовувати Link і у вкладених layout:
// app/dashboard/layout.tsx
import Link from "next/link";
export default function DashboardLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<section>
<aside>
<nav aria-label="Навігація кабінету">
<ul>
<li>
<Link href="/dashboard">Огляд</Link>
</li>
<li>
<Link href="/dashboard/settings">Налаштування</Link>
</li>
</ul>
</nav>
</aside>
<div>{children}</div>
</section>
);
}Компоненти спільного інтерфейсу краще робити невеликими та відповідальними за одну частину сторінки:
components/
Header.tsx
Logo.tsx
Navigation.tsx
Footer.tsxНаприклад:
Header об'єднує логотип і навігацію;
Navigation містить посилання;
Footer відповідає за підвал.
Такий поділ спрощує повторне використання та зміну окремих частин інтерфейсу.
Не потрібно писати Header у кожному page.tsx:
export default function Page() {
return (
<>
<Header />
<h1>Сторінка</h1>
<Footer />
</>
);
}Якщо ці елементи потрібні на всіх сторінках, підключіть їх у app/layout.tsx.
Для внутрішніх маршрутів використовуйте Link:
import Link from "next/link";
<Link href="/about">Про нас</Link>Не використовуйте для цього window.location або зайві обробники подій. Link призначений саме для навігації між маршрутами Next.js.
children у layoutLayout повинен відображати children. Інакше вміст сторінок не буде показаний:
export default function Layout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<div>
{children}
</div>
);
}Layout має містити спільну структуру, але не вміст конкретної сторінки. Заголовок статті, список товарів або форму реєстрації слід залишати у відповідній сторінці чи компоненті.
Спільний інтерфейс складається з елементів, які використовуються на кількох сторінках.
Компоненти Header, Navigation і Footer можна зберігати окремо в папці components.
app/layout.tsx обгортає всі сторінки застосунку.
Вміст поточної сторінки передається в layout через children.
Для внутрішньої навігації використовуйте Link з next/link.
Для окремої частини застосунку можна створити вкладений layout.