Custom Document

A custom Document is commonly used to augment your application’s <html> and <body> tags. This is necessary because Next.js pages skip the definition of the surrounding document’s markup.

To override the default Document, create the file ./pages/_document.js and extend the Document class as shown below:

  1. import Document, { Html, Head, Main, NextScript } from 'next/document'
  2. class MyDocument extends Document {
  3. static async getInitialProps(ctx) {
  4. const initialProps = await Document.getInitialProps(ctx)
  5. return { ...initialProps }
  6. }
  7. render() {
  8. return (
  9. <Html>
  10. <Head />
  11. <body>
  12. <Main />
  13. <NextScript />
  14. </body>
  15. </Html>
  16. )
  17. }
  18. }
  19. export default MyDocument

The code above is the default Document added by Next.js. Feel free to remove the getInitialProps or render function from MyDocument if you don’t need to change them.

<Html>, <Head />, <Main /> and <NextScript /> are required for the page to be properly rendered.

Custom attributes are allowed as props, like lang:

  1. <Html lang="en">

The <Head /> component used here is not the same one from next/head. The <Head /> component used here should only be used for any <head> code that is common for all pages. For all other cases, such as <title> tags, we recommend using next/head in your pages or components.

The ctx object is equivalent to the one received in getInitialProps, with one addition:

  • renderPage: Function - a callback that runs the actual React rendering logic (synchronously). It’s useful to decorate this function in order to support server-rendering wrappers like Aphrodite’s renderStatic

Caveats

  • Document is only rendered in the server, event handlers like onClick won’t work
  • React components outside of <Main /> will not be initialized by the browser. Do not add application logic here or custom CSS (like styled-jsx). If you need shared components in all your pages (like a menu or a toolbar), take a look at the App component instead
  • Document‘s getInitialProps function is not called during client-side transitions, nor when a page is statically optimized

Customizing renderPage

It should be noted that the only reason you should be customizing renderPage is for usage with css-in-js libraries that need to wrap the application to properly work with server-side rendering.

It takes as argument an options object for further customization:

  1. import Document from 'next/document'
  2. class MyDocument extends Document {
  3. static async getInitialProps(ctx) {
  4. const originalRenderPage = ctx.renderPage
  5. ctx.renderPage = () =>
  6. originalRenderPage({
  7. // useful for wrapping the whole react tree
  8. enhanceApp: (App) => App,
  9. // useful for wrapping in a per-page basis
  10. enhanceComponent: (Component) => Component,
  11. })
  12. // Run the parent `getInitialProps`, it now includes the custom `renderPage`
  13. const initialProps = await Document.getInitialProps(ctx)
  14. return initialProps
  15. }
  16. }
  17. export default MyDocument

TypeScript

You can use the built-in DocumentContext type and change the file name to ./pages/_document.tsx like so:

  1. import Document, { DocumentContext } from 'next/document'
  2. class MyDocument extends Document {
  3. static async getInitialProps(ctx: DocumentContext) {
  4. const initialProps = await Document.getInitialProps(ctx)
  5. return initialProps
  6. }
  7. }
  8. export default MyDocument