PolicyPage

Renders a typed PrivacyPolicy object as a full document — either inside a Shadow DOM root (default, opinionated styling) or inline in the host document (SSR-safe, your own typography).

Overview

PolicyPage is the renderer for the typed PrivacyPolicyobjects produced by AdaptivePolicyWizard, PolicyGenerator, or your own code. It delegates HTML generation to exportHTML(policy, options) under the hood, so the exported document and the rendered page are byte-for-byte identical.

Two render modes are available, each tuned for a different surface:

  • Shadow mode (default) — mounts the policy inside a Shadow DOM root, fully isolating the embedded <style> block. Use this for in-app embeds where you want the rich, opinionated default styling without polluting global CSS. Client-only.
  • Inline mode — injects the policy markup directly into the host document. Defaults to includeStyles: false so bare element selectors don't leak. Pair with your own CSS / design tokens. SSR-safe.

Exported from the /policy subpath:

import { PolicyPage } from '@tantainnovative/ndpr-toolkit/policy';

Quickstart

import { PolicyPage } from '@tantainnovative/ndpr-toolkit/policy';
import type { PrivacyPolicy } from '@tantainnovative/ndpr-toolkit';

export default function PrivacyRoute({ policy }: { policy: PrivacyPolicy }) {
  // Inline mode — crawlable markup, you supply the typography
  return (
    <article className="prose prose-slate dark:prose-invert max-w-3xl mx-auto">
      <PolicyPage policy={policy} mode="inline" />
    </article>
  );
}

Choosing a mode

ModeRendersSEOHost-CSS isolationBest for
'shadow' (default)Inside a Shadow DOM root, opinionated styles includedMarkup is invisible to crawlersStructurally impossible to leakIn-app embeds where you want a polished drop-in widget
'inline'Directly in the host document bodyCrawlable markupConsumer styles the markup themselvesSSR'd /privacy pages, public legal pages

Props

PropTypeDescription
policyPrivacyPolicyRequired. The typed policy object — usually obtained from the wizard's onComplete or your own builder.
mode'shadow' | 'inline'Render mode. Defaults to 'shadow'.
classNamestringClass applied to the wrapping <div> (the shadow host in shadow mode, the inline container otherwise).
optionsHTMLExportOptionsPass-through to exportHTML. Toggle includeStyles, includePrintCSS, inject customCSS, or pick a theme ('light' / 'dark' / 'auto'). Defaults differ by mode: shadow includes styles; inline omits them.

Inline-mode typography

The rendered markup is plain semantic HTML — <article>, <section>, <h2>, <p>, <ul>. Pair it with your own typography:

// Tailwind + @tailwindcss/typography
<article className="prose prose-slate dark:prose-invert max-w-3xl mx-auto">
  <PolicyPage policy={policy} mode="inline" />
</article>

// shadcn/ui card
<Card>
  <CardContent className="prose dark:prose-invert">
    <PolicyPage policy={policy} mode="inline" />
  </CardContent>
</Card>

// Raw CSS
// .ndpr-policy-page article { font-family: Georgia, serif; line-height: 1.7; }
// .ndpr-policy-page h2 { font-size: 1.5rem; margin-top: 2rem; }

Branding shadow mode

Stay in shadow mode and brand the policy by passing theme and customCSS through options:

<PolicyPage
  policy={policy}
  options={{
    theme: 'auto', // 'light' (default) | 'dark' | 'auto'
    customCSS: ':root { --color-accent: #1d4ed8; --max-width: 64rem; }',
  }}
/>