# Document and head (/docs/components/renderings/document-and-head)

> The document around a page: its head lines, the Theme's typefaces and browser color, its color scheme and one style element.

`document()` wraps a page body in its head and one stylesheet. Run the four steps of `renderPage` by hand and the result is the same string.

## Prerequisites

- The [quickstart](https://next.mdxui.dev/docs/start/quickstart) runs in your project, with `@mdxui/themes` installed as on [Packages and versions](https://next.mdxui.dev/docs/start/packages).

## Steps

1. Parse the record:

   ```ts
   const page = PageSchema.parse({
     theme: 'callboard',
     title: 'Harbor tides',
     description: 'Tide tables for every berth.',
     frame: 'none',
     sections: [
       { kind: 'hero', shell: { inset: 'contained', density: 'hero' }, block: { type: 'hero', layout: 'centered', stack: 560, title: 'Every berth, every tide.', lede: 'One call returns the tide table for any berth.', actions: [], fine: [] } },
       { kind: 'band', shell: { inset: 'contained', density: 'section' }, block: { type: 'statement', text: 'A tide table is a *promise*.' } },
       { kind: 'section', shell: { inset: 'contained', density: 'section' }, block: { type: 'command-row', command: 'npm i @example/harbor-tides' } },
     ],
   });
   ```

2. Render each section under the record's Theme, then compose the body:

   ```ts
   const { theme, css, head } = THEMES[page.theme];
   const sections = page.sections.map((s) => ({
     kind: s.kind,
     shell: s.shell,
     html: renderBlock(s.block, context(theme, s.shell.surface ?? 'paper', theme.icons)),
   }));
   const body = compose({ frame: page.frame, sections, dividers: theme.dividers });
   ```

3. Wrap the body. The Theme supplies the head lines and the tokens:

   ```ts
   const html = document({
     title: page.title,
     description: page.description,
     colorScheme: theme.dark && theme.scheme !== 'light' ? 'light dark' : 'light',
     jsonLd: page.jsonLd ?? [],
     head,
     css: `${css()}${baseCss}${primitivesCss}${shellCss}${blocksCss}`,
     body,
   });
   ```

4. Compare it with `renderPage`:

   ```ts
   if (html !== renderPage(page)) throw new Error('the document differs from renderPage');
   await writeFile('harbor.html', html);
   ```

## Result

The document equals `renderPage(page)` byte for byte; `pnpm check` runs the example and fails otherwise. With a `meta` of a canonical address and a type, its head reads:

| Head line | From |
| --- | --- |
| `<meta charset="utf-8">` | Fixed |
| `<meta name="viewport" content="width=device-width, initial-scale=1">` | Fixed |
| `<title>Harbor tides</title>` | `title` |
| `<meta name="description" content="Tide tables for every berth.">` | `description` |
| `<meta name="color-scheme" content="light">` | The Theme: `light dark` with a dark palette under `scheme: auto` |
| `<meta property="og:title" content="Harbor tides">` | `title`, `description` |
| `<meta property="og:description" content="Tide tables for every berth.…` | `title`, `description` |
| `<meta name="theme-color" content="#F4F6F8">` | The Theme's head lines |
| `<link rel="preconnect" href="https://fonts.googleapis.com">` | The Theme's head lines: its typefaces |
| `<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>` | The Theme's head lines: its typefaces |
| `<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family…` | The Theme's head lines: its typefaces |
| `<link rel="canonical" href="https://harbor.example/">` | `meta.canonical` |
| `<meta property="og:type" content="website">` | `meta.type` |

Then 1 `<style>` element: the Theme's tokens, the base, the primitives, the shell and every Section type.

## Related

  - [HTML](https://next.mdxui.dev/docs/components/renderings/html): The same document in one call.
  - [Typefaces](https://next.mdxui.dev/docs/themes/typefaces): The head lines each Theme loads.
  - [Share image](https://next.mdxui.dev/docs/components/renderings/share-image): What `meta.image` points at.

