Host integration

PageHubConfig shape, feature flags, callbacks, locale, AI config.

Everything you need to wire the SDK into your app, in one config object. Pass it to <PageHubProvider config={...}> (React) or PageHub.init(...) (vanilla JS). Same shape, same fields, same behavior.

Looking for the full TypeScript type? See PageHubConfig in types.ts. This doc covers what each field is for and when you'd reach for it — the type file is the source of truth for the shape.


The smallest config that works

import { PageHubEditor } from "@pagehub/sdk";

<PageHubEditor
  callbacks={{
    onLoad: async () => fetch("/api/page").then(r => r.json()),
    onSave: async data =>
      fetch("/api/page", { method: "PUT", body: JSON.stringify(data) }),
  }}
/>;

That's it. Two callbacks. Everything else is optional.


A fully wired config

The same config shape supports as much customization as you want to layer on:

<PageHubEditor
  // ─── Mount ─────────────────────────────────────────
  apiBaseUrl="https://my-app.com/api"
  pageId="home"
  readOnly={false}

  // ─── Required: callbacks ───────────────────────────
  callbacks={{ onLoad, onSave, onPublish, onMediaUpload }}

  // ─── Visual customization ──────────────────────────
  theme={{ primaryColor: "#2563eb", logo: "/my-logo.svg" }}
  features={{ aiGeneration: true, customCSS: false }}
  locale={{ language: "en", strings: { /* overrides */ } }}

  // ─── Component extensions ──────────────────────────
  components={[MyPricingCard, MyChart]}
  presets={{ Container: [...containerPresets, ...mine] }}
  modifiers={{ Button: [...buttonModifiers, ...mine] }}

  // ─── Host-rendered chrome ──────────────────────────
  aiPanel={<MyAiAssistant />}
  editorChromeSlots={{ siteSettingsExtraTabs: [...] }}

  // ─── Picker tuning ─────────────────────────────────
  curatedGoogleFontFamilies={{ popular: [...] }}
  viewportDevicePresets={[{ name: "iPhone 15", width: 393, height: 852, dpr: 3 }]}

  // ─── Misc ──────────────────────────────────────────
  apiKey={process.env.PAGEHUB_API_KEY}
  cdn={{ accountHash: "abc123" }}
  urlStrategy="pushState"
/>;

Everything below explains each section in detail.


Mount fields

FieldTypeWhat it does
containerHTMLElement | stringVanilla JS only — the DOM node (or selector) to mount into. React users skip this.
pageIdstringInitial page to load. If omitted, the SDK calls onLoad(undefined) and you decide.
readOnlybooleanStart in viewer mode (no editor chrome). Default false.
apiBaseUrlstringBase URL for SDK-managed server calls (AI, media uploads, etc.). Required for any feature that talks to your server.
apiKeystringPageHub Cloud API key. Skip this when you're self-hosted.

Callbacks (required)

callbacks is the only required field. Two functions get you running; the rest are opt-in. See PageHubCallbacks in types.ts for the full list.

callbacks: {
  // Required
  onLoad: async pageId => fetch(...),               // return PageData | null
  onSave: async (data, meta) => fetch(...),         // persist

  // Common opt-ins
  onChange: data => {},                             // every edit (debounced)
  onPublish: async data => fetch(...),              // user hit Publish
  onMediaUpload: async file => uploadAndReturnUrl,  // file uploads
  onMediaDelete: async url => fetch(...),           // file deletes
}

onSave receives a PageData object containing content (compressed editor state — store this to reload later), html (rendered static HTML), classes (Tailwind classes for purging), title, and seo.


Theme

Quick brand customization. For full theming see theme.md.

theme: {
  primaryColor: "#2563eb",
  secondaryColor: "#7c3aed",
  accentColor: "#06b6d4",
  colorScheme: "system",          // "light" | "dark" | "system"
  logo: "/my-logo.svg",           // shown in editor toolbar
  cssVariables: { brand: "#f00" }, // any CSS var, no `--` prefix needed
  customCSS: "/* injected raw */",
}

Features

Turn editor capabilities on or off. See PageHubFeatures in types.ts for the full list.

features: {
  sidebar: true,             // component panel (toolbox)
  toolbar: true,             // top toolbar
  aiGeneration: false,       // AI content generation (needs `ai` config)
  multiPage: true,           // multi-page site editing
  responsivePreview: true,   // device preview toggle
  seoPanel: true,            // SEO settings panel
  importExport: false,       // JSON import/export UI
  customCSS: false,          // CSS editor panel
  restrictedComponents: [],  // deny-list (use `registerComponentAllowlist` for allow-list)
}

For constrained modes (email, kiosk) where you want to lock down the editor instead of just toggling features, see host-constraints.md.


AI

ai: { enabled: true }

Drives the AI assistant button + the panel slot. To actually render an assistant UI, also provide aiPanel: <YourAssistant /> — the SDK gives you a layout slot; you own the API calls and the UI.


Locale

Override built-in strings, format dates, etc. See PageHubLocale in types.ts.

locale: {
  language: "en",
  strings: { "editor.save": "Salvar" },
}

Component extensions

Three ways to extend the catalog. All optional; all composable.

Custom components

Build your own draggable component. One function, one config field. See registration-host.md for the full guide.

import { defineComponent } from "@pagehub/sdk";

const PricingCard = defineComponent({ name: "PricingCard", component: ..., toHTML: ... });

<PageHubEditor components={[PricingCard]} />

Presets / modifiers

Add variant chips to existing components. Replaces the built-in list — use the @pagehub/sdk/presets/<component> sub-path to compose with built-ins:

import { containerPresets } from "@pagehub/sdk/presets/container";

<PageHubEditor
  presets={{ Container: [...containerPresets, myCustomPreset] }}
  modifiers={{ Button: [...buttonModifiers, myCustomModifier] }}
/>

You can also register these at runtime via registerPresets / registerModifiers — see extensibility.md.


Host-rendered chrome

The SDK gives you slots inside its UI; you render whatever React you want.

FieldSlot
aiPanelDocked AI assistant panel (shown when features.aiGeneration is true).
editorChromeSlots.siteSettingsExtraTabsExtra tabs inside the Site Settings modal (e.g. Data Connectors).
editorChromeSlots.pageSettingsExtraTabsExtra tabs inside the Page Settings modal.
editorChromeSlots.renderMediaEditAiActionsAI action block inside the Media edit modal.

The SDK provides layout and styling primitives; the host owns API calls, auth, and business logic. Use the useSDK() hook inside your components if you need the SDK emitter or config.


Picker tuning

Two narrow knobs that shape specific UI surfaces. Most apps never touch these.

curatedGoogleFontFamilies

Shapes the editor's font picker — the two rails (popular, funky) and the offline extended fallback list. Does not affect what fonts ship to published sites (that's driven by styleGuide + font-* classes on the page).

curatedGoogleFontFamilies: {
  popular: ["Inter", "Space Grotesk", "Geist"],
  funky: ["Bagel Fat One", "Caprasimo"],
  extended: ["Roboto", "Lato", /* ...used when Google Fonts API is down */],
}

Default: DEFAULT_CURATED_GOOGLE_FONT_FAMILIES. Spread from it if you only want to tweak one rail.

Tip: memoize the config object (or this field) when building inline — a new identity on every render re-runs the sync effect and wipes the in-memory fonts cache.

viewportDevicePresets

Drives the device-mode dropdown in the responsive preview chrome.

viewportDevicePresets: [
  { name: "iPhone 15", width: 393, height: 852, dpr: 3 },
  { name: "iPad", width: 820, height: 1180, dpr: 2 },
  { name: "Custom", width: 1280, height: 800, dpr: 1 },
]

Default: DEFAULT_VIEWPORT_DEVICE_PRESETS. Include a "Custom" row if you want the same manual-resize UX as the stock list.


Misc

FieldWhat it does
cdnCloudflare Images delivery config — accountHash, baseUrl, variant. Required if you use the built-in image upload pipeline.
urlStrategy"pushState" makes browser back / forward navigate between pages. Omit for in-memory-only switching.

Where to go from here