Skip to content

Document Customization

Pareto lets you customize the <html> element attributes by creating an app/document.tsx file at the root of your app directory. This is useful for setting lang, dir, theme attributes, or any other HTML attribute based on the current request.

Create app/document.tsx and export a getDocumentProps function:

app/document.tsx
import type { GetDocumentProps } from '@paretojs/core'
export const getDocumentProps: GetDocumentProps = ({ pathname }) => {
const lang = pathname.startsWith('/zh') ? 'zh' : 'en'
return {
lang,
dir: lang === 'ar' || lang === 'he' ? 'rtl' : 'ltr',
}
}

The returned object is spread onto the <html> element. Common attributes like lang, dir, and className are typed explicitly for convenience, but you can return any string attribute.

  • ServergetDocumentProps runs on every request. The returned attributes are applied to the <html> element in the SSR HTML output.
  • Client navigation — When the user navigates client-side, Pareto re-runs getDocumentProps and syncs the attributes onto document.documentElement. Stale attributes from the previous page are automatically removed.

This means your <html> attributes stay correct across both server-rendered pages and client-side navigations without any manual DOM manipulation.

The getDocumentProps function receives a DocumentContext object:

interface DocumentContext {
req: Request
params: Record<string, string>
pathname: string
loaderData: unknown
}
PropertyDescription
reqThe Express request object
paramsDynamic route parameters (e.g. { slug: 'hello' })
pathnameThe current URL path
loaderDataData returned by the route’s loader

You can use any of these to determine what attributes to set. For example, you could read a cookie from req to set a theme, or use loaderData to set attributes based on fetched content.

Set lang and dir based on the URL or route parameters:

export const getDocumentProps: GetDocumentProps = ({ params }) => {
const lang = params.lang || 'en'
return {
lang,
dir: lang === 'ar' || lang === 'he' ? 'rtl' : 'ltr',
}
}

Apply a theme class or data attribute:

export const getDocumentProps: GetDocumentProps = ({ req }) => {
const theme = req.cookies?.theme || 'light'
return {
'data-theme': theme,
className: theme,
}
}

Pass any data attribute for use by client-side scripts or CSS:

export const getDocumentProps: GetDocumentProps = ({ pathname }) => ({
lang: 'en',
'data-page': pathname.split('/')[1] || 'home',
})

getDocumentProps returns an HtmlAttributes object:

type HtmlAttributes = Record<string, string> & {
lang?: string
dir?: string
className?: string
}

All keys are applied as attributes on the <html> element. The className key maps to the HTML class attribute.