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
PageHubConfigintypes.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.
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.
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.
| Field | Type | What it does |
|---|---|---|
container | HTMLElement | string | Vanilla JS only — the DOM node (or selector) to mount into. React users skip this. |
pageId | string | Initial page to load. If omitted, the SDK calls onLoad(undefined) and you decide. |
readOnly | boolean | Start in viewer mode (no editor chrome). Default false. |
apiBaseUrl | string | Base URL for SDK-managed server calls (AI, media uploads, etc.). Required for any feature that talks to your server. |
apiKey | string | PageHub Cloud API key. Skip this when you're self-hosted. |
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.
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 */",
}
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: { 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.
Override built-in strings, format dates, etc. See PageHubLocale in types.ts.
locale: {
language: "en",
strings: { "editor.save": "Salvar" },
}
Three ways to extend the catalog. All optional; all composable.
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]} />
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.
The SDK gives you slots inside its UI; you render whatever React you want.
| Field | Slot |
|---|---|
aiPanel | Docked AI assistant panel (shown when features.aiGeneration is true). |
editorChromeSlots.siteSettingsExtraTabs | Extra tabs inside the Site Settings modal (e.g. Data Connectors). |
editorChromeSlots.pageSettingsExtraTabs | Extra tabs inside the Page Settings modal. |
editorChromeSlots.renderMediaEditAiActions | AI 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.
Two narrow knobs that shape specific UI surfaces. Most apps never touch these.
curatedGoogleFontFamiliesShapes 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.
viewportDevicePresetsDrives 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.
| Field | What it does |
|---|---|
cdn | Cloudflare 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. |