Adds a routing guide section for `404.md` and per-locale pages, documents
`themeConfig.notFound` and `Theme.NotFound`, and updates the custom theme,
default theme, i18n, site config and runtime API pages accordingly.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Content of the not-found page when the site has no `404.md`
* @optional
*/
NotFound?: Component
/**
* Enhance Vue app instance
* @optional
@ -130,9 +135,21 @@ The most basic layout component needs to contain a [`<Content />`](../reference/
</template>
```
The above layout simply renders every page's markdown as HTML. The first improvement we can add is to handle 404 errors:
The above layout renders every page's markdown as HTML. That includes the not-found page: when a visitor opens a URL that has no page, `<Content />` renders the site's `404.md`, or the theme's `NotFound` component when the site has none. A theme should ship that component, so every site gets a not-found page without writing one. Without it, a small unstyled built-in page is shown instead.
```js [.vitepress/theme/index.js]
import Layout from './Layout.vue'
import NotFound from './NotFound.vue'
export default {
Layout,
NotFound
}
```
The [`useData()`](../reference/runtime-api#usedata) helper provides us with all the runtime data we need to conditionally render different layouts. For example, `page.isNotFound` is `true` on the not-found page, so the layout can leave out the parts that only make sense for real pages:
```vue{1-4,9-12}
```vue{1-4,9}
<scriptsetup>
import { useData } from 'vitepress'
const { page } = useData()
@ -141,14 +158,12 @@ const { page } = useData()
<template>
<h1>Custom Layout!</h1>
<divv-if="page.isNotFound">
Custom 404 page!
</div>
<Contentv-else/>
<asidev-if="!page.isNotFound">Table of contents</aside>
<Content/>
</template>
```
The [`useData()`](../reference/runtime-api#usedata) helper provides us with all the runtime data we need to conditionally render different layouts. One of the other data we can access is the current page's frontmatter. We can leverage this to allow the end user to control the layout in each page. For example, the user can indicate the page should use a special home page layout with:
One of the other data we can access is the current page's frontmatter. We can leverage this to allow the end user to control the layout in each page. For example, the user can indicate the page should use a special home page layout with:
Each locale directory can also have its own [`404.md`](./routing#not-found-page). A locale without one shares the root `404.md`.
However, VitePress won't redirect `/` to `/en/` by default. You'll need to configure your server for that. For example, on Netlify, you can add a `docs/public/_redirects` file like this:
@ -151,6 +151,28 @@ If, however, you cannot configure your server with such support, you will have t
└─ index.md
```
## Not Found Page
When a visitor opens a URL that has no page, VitePress shows the not-found page. The default theme ships one, and you can change its text with the [`notFound`](../reference/default-theme-config#notfound) theme option.
To replace the page entirely, add a `404.md` file to your source directory. It is a regular page: frontmatter, Markdown and Vue components all work.
```md [404.md]
---
title: Page not found
---
# Page not found
The page you are looking for does not exist. [Go to the homepage](/).
```
With [multiple locales](./i18n), each locale directory can have its own `404.md`, for example `zh/404.md`. A locale without one uses the root `404.md`, and the theme's default page when there is none either.
The build emits `404.html` at the output root and one in each locale directory. Most hosts pick up `404.html` automatically, see the [deployment guide](./deploy). The dev and preview servers answer a miss with a real 404 status too.
On the not-found page, `useData().page.isNotFound` is `true` and `useRoute().path` holds the URL the visitor asked for. The page is left out of the sitemap and the local search index.
## Route Rewrites
You can customize the mapping between the source directory structure and the generated pages. It's useful when you have a complex project structure. For example, let's say you have a monorepo with multiple packages, and would like to place documentations along with the source files like this:
Customizes the text of the not-found page. Set it under `locales.<locale>.themeConfig` to translate it. To replace the whole page, add a [`404.md`](../guide/routing#not-found-page) to your site instead.
```ts
export interface NotFoundOptions {
/**
* Set custom not found message.
*
* @default 'PAGE NOT FOUND'
*/
title?: string
/**
* Set custom not found description.
*
* @default "But if you don't change your direction, and if you keep looking, you may end up where you are heading."
*/
quote?: string
/**
* Target of the home link. Defaults to the home of the current locale.
*/
link?: string
/**
* Set custom home link text.
*
* @default 'Take me home'
*/
linkText?: string
/**
* @default '404'
*/
code?: string
}
```
**Example:**
```ts
export default {
themeConfig: {
notFound: {
title: 'Nothing here',
quote: 'The page you are looking for may have moved.',
linkText: 'Back to the docs'
}
}
}
```
## darkModeSwitchLabel
- Type: `string`
@ -521,6 +576,7 @@ Returns layout-related data. The returned object has the following type:
`page.headers` is populated only when [`markdown.headers`](./site-config#markdown) is enabled. Without that option, it remains an empty array. The default theme outline reads rendered headings from the page content, so it can still appear when `page.headers` is empty.
`page.isNotFound` is `true` on the [not-found page](../guide/routing#not-found-page), which also answers every URL that has no page. `useRoute().path` still holds the URL the visitor asked for.