Пошук уроків, статей та іншого контенту
Розберете структуру Metadata API та правила опису заголовків, описів і метаданих сторінки.
Metadata API у Next.js App Router дає змогу описувати метадані сторінок у файлах layout.tsx і page.tsx.
Метадані — це інформація про сторінку, яку використовують:
вкладка браузера;
пошукові системи;
соціальні мережі;
браузери та інші клієнти.
Найчастіше потрібно налаштувати:
заголовок сторінки;
опис сторінки;
ключові слова;
автора;
правила індексації.
Next.js на основі об’єкта metadata автоматично створює відповідні HTML-теги в секції <head>.
Статичні метадані підходять для сторінок, інформація про які не змінюється залежно від URL або даних.
У файлі layout.tsx або page.tsx потрібно експортувати змінну metadata типу Metadata.
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Головна сторінка",
description: "Опис головної сторінки сайту",
};
export default function HomePage() {
return (
<main>
<h1>Головна сторінка</h1>
<p>Вітаємо на нашому сайті.</p>
</main>
);
}У результаті Next.js сформує приблизно такі HTML-метадані:
<title>Головна сторінка</title>
<meta name="description" content="Опис головної сторінки сайту">Імпорт Metadata потрібен для перевірки структури об’єкта під час розробки та компіляції.
layout.tsxМетадані, оголошені в кореневому layout.tsx, можуть бути спільними для всього сайту.
Приклад структури проєкту:
app/
├── layout.tsx
├── page.tsx
└── about/
└── page.tsxФайл app/layout.tsx:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: {
default: "Мій сайт",
template: "%s | Мій сайт",
},
description: "Сайт із корисними матеріалами для розробників",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="uk">
<body>{children}</body>
</html>
);
}Файл app/page.tsx:
export default function HomePage() {
return (
<main>
<h1>Головна сторінка</h1>
</main>
);
}У цьому випадку для головної сторінки буде використано:
title: Мій сайт
description: Сайт із корисними матеріалами для розробниківФайл app/about/page.tsx може мати власний заголовок:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Про нас",
description: "Дізнайтеся більше про нашу команду",
};
export default function AboutPage() {
return (
<main>
<h1>Про нас</h1>
</main>
);
}Оскільки в layout.tsx задано шаблон заголовка, фактичний заголовок сторінки буде:
Про нас | Мій сайтОпис сторінки буде взято з app/about/page.tsx, адже дочірня сторінка має власне значення description.
titleПоле title може мати просте текстове значення:
export const metadata: Metadata = {
title: "Про нас",
};Також title може бути об’єктом із трьома основними властивостями:
export const metadata: Metadata = {
title: {
default: "Мій сайт",
template: "%s | Мій сайт",
absolute: "Фіксований заголовок",
},
};defaultdefault — заголовок, який використовується тоді, коли дочірня сторінка не визначила власний title.
export const metadata: Metadata = {
title: {
default: "Мій сайт",
template: "%s | Мій сайт",
},
};Якщо сторінка не має власного заголовка, її заголовком буде:
Мій сайтtemplatetemplate — шаблон для заголовків дочірніх сторінок. Позначення %s замінюється значенням title сторінки.
export const metadata: Metadata = {
title: {
default: "Мій сайт",
template: "%s | Мій сайт",
},
};Якщо дочірня сторінка має:
export const metadata: Metadata = {
title: "Контакти",
};результат буде:
Контакти | Мій сайтШаблон потрібно визначати в layout.tsx. Він не застосовується до сторінок, які є батьківськими для цього layout.
absoluteabsolute задає заголовок без застосування шаблона з батьківського layout.
export const metadata: Metadata = {
title: {
absolute: "Спеціальний заголовок",
},
};Навіть якщо layout містить шаблон "%s | Мій сайт", результатом буде тільки:
Спеціальний заголовокdescriptiondescription — короткий опис сторінки.
export const metadata: Metadata = {
title: "Каталог",
description: "Перегляньте каталог доступних товарів",
};Next.js створить метатег:
<meta
name="description"
content="Перегляньте каталог доступних товарів"
/>Для кожної важливої сторінки варто вказувати власний опис. Він має:
описувати саме поточну сторінку;
бути зрозумілим без додаткового контексту;
не складатися з випадкового набору ключових слів;
відповідати вмісту сторінки.
Об’єкт Metadata може містити багато властивостей. Наприклад:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Документація",
description: "Документація нашого продукту",
keywords: ["Next.js", "React", "документація"],
authors: [{ name: "Команда розробки" }],
robots: {
index: true,
follow: true,
},
};Основні властивості цього прикладу:
keywords — масив ключових слів;
authors — інформація про авторів;
robots.index — чи дозволено індексувати сторінку;
robots.follow — чи дозволено переходити за посиланнями на сторінці.
Для звичайної сторінки часто достатньо title і description. Інші поля слід додавати лише тоді, коли вони справді потрібні.
Next.js може об’єднувати метадані з кількох layout і сторінки.
Наприклад:
app/layout.tsx
app/blog/layout.tsx
app/blog/page.tsxМетадані з app/layout.tsx є базовими. Layout для blog і сторінка блогу можуть додати або змінити окремі значення.
Якщо кілька рівнів визначають однакове поле, ближче до сторінки значення має вищий пріоритет.
Наприклад, якщо кореневий layout містить:
export const metadata: Metadata = {
description: "Загальний опис сайту",
};а сторінка містить:
export const metadata: Metadata = {
description: "Опис сторінки блогу",
};для сторінки буде використано:
Опис сторінки блогуНе потрібно дублювати однакові метадані в кожному файлі. Загальні значення зручно розміщувати в layout, а унікальні — у відповідних сторінках.
Іноді заголовок і опис залежать від даних. Наприклад, сторінка статті може отримувати назву за ідентифікатором у URL.
Для таких випадків використовується функція generateMetadata.
import type { Metadata } from "next";
type ArticlePageProps = {
params: Promise<{
slug: string;
}>;
};
type Article = {
title: string;
description: string;
};
async function getArticle(slug: string): Promise<Article> {
return {
title: `Стаття: ${slug}`,
description: `Опис статті з ідентифікатором ${slug}`,
};
}
export async function generateMetadata({
params,
}: ArticlePageProps): Promise<Metadata> {
const { slug } = await params;
const article = await getArticle(slug);
return {
title: article.title,
description: article.description,
};
}
export default async function ArticlePage({
params,
}: ArticlePageProps) {
const { slug } = await params;
const article = await getArticle(slug);
return (
<main>
<h1>{article.title}</h1>
<p>{article.description}</p>
</main>
);
}Такий файл можна розмістити за маршрутом:
app/articles/[slug]/page.tsxДля URL /articles/nextjs функція сформує метадані на основі значення slug.
generateMetadata повинна повертати об’єкт типу Metadata. Її можна використовувати замість статичного експорту metadata, але не потрібно оголошувати обидва варіанти для однієї сторінки.
Metadata API призначений для серверної частини App Router. Експорт metadata або generateMetadata не можна використовувати у файлі, який має директиву:
"use client";Якщо компонент повинен бути клієнтським, метадані слід визначити в батьківському серверному layout або page.
Структура:
app/
├── layout.tsx
└── page.tsxapp/layout.tsx:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: {
default: "Курс Next.js",
template: "%s | Курс Next.js",
},
description: "Навчальні матеріали з розробки на Next.js",
authors: [{ name: "Команда курсу" }],
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="uk">
<body>{children}</body>
</html>
);
}app/page.tsx:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Головна",
description: "Головна сторінка курсу Next.js",
};
export default function HomePage() {
return (
<main>
<h1>Курс Next.js</h1>
<p>Вивчайте розробку вебзастосунків із Next.js.</p>
</main>
);
}У браузері заголовок сторінки буде:
Головна | Курс Next.jsа опис сторінки буде:
Головна сторінка курсу Next.jsmetadata у Client Component"use client";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Помилка",
};Це неправильний підхід. Файли з metadata або generateMetadata не повинні бути Client Components.
Шаблон заголовка потрібно визначати в layout:
export const metadata: Metadata = {
title: {
template: "%s | Мій сайт",
},
};На самій сторінці достатньо вказати:
export const metadata: Metadata = {
title: "Блог",
};defaultЯкщо в layout є тільки template, але немає default, для сторінок без власного заголовка може не бути очікуваного базового значення.
Краще визначати обидва поля:
export const metadata: Metadata = {
title: {
default: "Мій сайт",
template: "%s | Мій сайт",
},
};Загальний опис у layout зручний як значення за замовчуванням, але важливі сторінки мають отримувати власні описи. Опис сторінки повинен відповідати її реальному вмісту.
<title> у компонентДля App Router не потрібно додавати <title> вручну в JSX. Для цього використовується Metadata API:
export const metadata: Metadata = {
title: "Моя сторінка",
};Metadata API використовується в App Router для опису метаданих сторінок.
Статичні метадані експортуються як metadata.
Динамічні метадані створюються за допомогою generateMetadata.
Загальні метадані зручно визначати в layout.tsx.
Унікальні метадані сторінки визначаються в її page.tsx.
title може бути рядком або об’єктом із default, template та absolute.
%s у template замінюється заголовком дочірньої сторінки.
Ближчі до сторінки значення мають пріоритет над значеннями батьківського layout.
metadata і generateMetadata не використовуються в Client Components.