docs/app/docs/file-conventions/meta-file/page.mdx
import { ContentAndAppFileTee } from 'components/content-and-app-file-tree' import { Video } from 'components/video' import { FileTree } from 'nextra/components' import { generateTsFromZod } from 'nextra/tsdoc' import { pageThemeSchema } from 'private-next-root-dir/../packages/nextra/dist/server/schemas'
export function Block({ children }) { return ( <div className="flex gap-2 *:last:w-full *:last:min-w-0 max-lg:flex-wrap"> {children} </div> ) }
_meta.js FileIn Nextra, the site and individual page structure can be configured via the
co-located _meta files. Those configurations affect the overall layout of your
Nextra theme, especially the navigation bar and the sidebar:
Nextra allows you to organize files in the following ways:
In Next.js'
app directory:
Nextra
gathers all page files, including
page.md and page.mdx files as well as
_meta files.
In Nextra's
content directory:
Nextra
collects all .md and .mdx files, along with _meta files.
Below the same file-based routing structure is represented for content and
app-only directories:
[!NOTE]
You can combine both organizational ways for your project:
- the
contentdirectory with.mdxfiles- the
appdirectory withpagefiles
pageMap structureAfterward, Nextra generates a pageMap array containing information about your
entire site's routes and directories structure. Features such as the navigation
bar and sidebar can be generated based on the pageMap information.
The generated pageMap will be:
[
// content/_meta.js
{ "data": {} },
{
// content/index.mdx
"name": "index",
"route": "/",
"title": "Index",
"frontMatter": {}
},
{
// content/contact.md
"name": "contact",
"route": "/contact",
"title": "Contact",
"frontMatter": {}
},
{
// content/about
"name": "about",
"route": "/about",
"title": "About",
"children": [
// content/about/_meta.js
{ "data": {} },
{
// content/about/index.mdx
"name": "index",
"route": "/about",
"title": "Index",
"frontMatter": {}
},
{
// content/about/legal.md
"name": "legal",
"route": "/about/legal",
"title": "Legal",
"frontMatter": {}
}
]
}
]
And the global pageMap will be imported to each page by Nextra. Then,
configured theme will render the actual UI with that pageMap.
The title and order of a page shown in the sidebar/navbar can be configured in
the _meta file as key-value pairs.
import type { MetaRecord } from 'nextra'
/**
* type MetaRecordValue =
* | TitleSchema
* | PageItemSchema
* | SeparatorSchema
* | MenuSchema
*
* type MetaRecord = Record<string, MetaRecordValue>
**/
const meta: MetaRecord = {
// ...
}
export default meta
title typeWhen specifying a title in _meta file, you can define it as either a simple
string or a JSX element.
type TitleSchema = string | ReactElement
For the below file structure:
<ContentAndAppFileTee className="shrink-0"> <FileTree.File name="_meta.js" active /> <FileTree.File name="about.mdx" /> <FileTree.File name="contact.mdx" /> <FileTree.File name="index.mdx" /> </ContentAndAppFileTee>The following _meta file defines pages titles:
import { GitHubIcon } from 'nextra/icons'
export default {
index: 'My Homepage',
// You can use JSX elements to change the look of titles in the sidebar, e.g. insert icons
contact: (
<Italic className="my-class">
<GitHubIcon height="20" />
Contact Us
</Italic>
),
about: {
// Alternatively, you can set title with `title` property
title: 'About Us'
// ... and provide extra configurations
}
}
// Custom component for italicized text
function Italic({ children, ...props }) {
return <i {...props}>{children}</i>
}
In _meta file you can define how the pages are shown in the sidebar, e.g. for
the following file structure:
[!NOTE]
If any routes are not listed in the
_metafile, they will be appended to the end of the sidebar and sorted alphabetically (except forindexkey which comes first if it's not specified in_metafile).
type PageItemSchema = {
type: 'page' | 'doc' // @default 'doc'
display: 'normal' | 'hidden' | 'children' // @default 'normal'
title?: TitleSchema
theme?: PageThemeSchema
}
type: 'page' optionBy defining a top-level page or folder as type: 'page'{:js}, it will be shown
as a special page on the navigation bar, instead of the sidebar. With this
feature, you can have multiple "sub docs", and special pages or links such as
"Contact Us" that are always visible.
For example, you can have 2 docs folders frameworks and fruits in your
project. In your top-level _meta file, you can set everything as a page,
instead of a normal sidebar item:
And it will look like this:
<figure> <Video src="/assets/docs/sub-docs.mp4" /> <figcaption>[Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-eszspq?file=pages%2F_meta.js)</figcaption> </figure>[!TIP]
You can also hide links like
Homefrom the navbar with thedisplay: 'hidden'{:js}option.You can have external links in the navbar, similar to the links section:
jsexport default { contact: { title: 'Contact Us', type: 'page', href: 'https://example.com/contact' } }
display: 'hidden' optionBy default, all MDX routes in the filesystem will be shown on the sidebar. But
you can hide a specific pages or folders by using the display: 'hidden'{:ts}
configuration:
export default {
contact: {
display: 'hidden'
}
}
[!NOTE]
The page will still be accessible via the
/contactURL, but it will not be shown in the sidebar.
theme optionYou can configure the theme for each page using the theme option. For example,
you can disable or enable specific components for specific pages:
export default {
about: {
theme: {
sidebar: false
}
}
}
[!WARNING]
This option will be inherited by all child pages if set to a folder.
<APIDocs
code={type $ = ${generateTsFromZod(pageThemeSchema)} export default $}
/>
By default, each page has layout: 'default'{:js} in their theme config, which
is the default behavior. You might want to render some page with the full
container width and height, but keep all the other styles. You can use the
'full'{:js} layout to do that:
export default {
about: {
theme: {
layout: 'full'
}
}
}
The typesetting option controls typesetting details like font features,
heading styles and components like <li> and <code>. There are
'default'{:js} and 'article'{:js} typesettings available in the docs theme.
The default one is suitable for most cases like documentation, but you can use
the 'article'{:js} typesetting to make it look like an elegant article page:
Folders can be configured in the same way as pages.
For example, the following top-level _meta file contains the meta information
for the top-level pages and folders.
The nested _meta file contains the
meta information for pages in the same folder:
[!NOTE]
You can move directories around without having to change the
_metafile since information for pages are grouped together in directories.
/index pageTo create a folder with an index page, add asIndexPage: true{:js} to its front
matter.
For example, to create a /fruits route, setting asIndexPage: true{:js} tells
Nextra that /fruits is a folder with an index page. Clicking the folder in the
sidebar will expand it and display the MDX page.
type LinkSchema = {
href: string
title?: TitleSchema
}
You can add external links to the sidebar by adding an item with href in
_meta file:
export default {
github_link: {
title: 'Nextra',
href: 'https://github.com/shuding/nextra'
}
}
[!TIP]
You can use this option to link to relative internal links too.
type SeparatorSchema = {
type: 'separator'
title?: TitleSchema
}
You can use a "placeholder" item with type: 'separator'{:js} to create a
separator line between items in the sidebar:
export default {
'###': {
type: 'separator',
title: 'My Items' // Title is optional
}
}
You can also add menus to the navbar using type: 'menu'{:js} and the items
option:
type MenuItemSchema =
| TitleSchema
| { title: TitleSchema }
| (LinkSchema & { type?: 'page' | 'doc' })
| SeparatorSchema
type MenuSchema = {
type: 'menu'
title?: TitleSchema
items: Record<string, MenuItemSchema>
}
export default {
company: {
title: 'Company',
type: 'menu',
items: {
about: {
title: 'About',
href: '/about'
},
contact: {
title: 'Contact Us',
href: 'mailto:[email protected]'
}
}
}
}
In the type: 'page'{:js} option above, we have to define
the type: 'page'{:js} option for every page. To make it easier, you can use
the '*' key to define the fallback configuration for all items in this folder:
export default {
'*': {
type: 'page'
},
index: 'Home',
frameworks: 'Frameworks',
fruits: 'Fruits',
about: 'About'
}
They are equivalent where all items have type: 'page'{:js} set.
_meta.global fileYou can also define all your pages in a single _meta file, suffixed with
.global. The API remains the same as for folder-specific _meta files, with 1
exception: folder items must include an items field.
For the following structure, you might use the following _meta files:
With single _meta.global file it can be defined as below:
export default {
fruits: {
type: 'page',
title: '✨ Fruits',
items: {
apple: '🍎 Apple',
banana: '🍌 BaNaNa'
}
}
}
[!WARNING]
You can't use both
_meta.globaland_metafiles in your project.
You can use ESLint's built-in sort-keys rule, append
/* eslint sort-keys: error */ comment at the top of your _meta file, and you
will receive ESLint's errors about incorrect order.
_meta keysThe type of your _meta keys should always be a string and not a number
because
numbers are always ordered first
in JavaScript objects.
For example, consider the following:
export default {
foo: '',
1992_10_21: '',
1: ''
}
will be converted to:
export default {
'1': '',
'19921021': '',
foo: ''
}
[!TIP]
The
.js,.jsx, or.tsxfile extensions can be used for_metafile.