Drop a full visual page builder into any web app.
A drag-and-drop page editor SDK built on CraftJS. Includes a visual canvas, component toolbox, settings panels, responsive preview, multi-page support, AI generation, SEO controls, and static HTML export — all configured through a single config object.
npm install @pagehub/sdkimport { PageHubEditor } from "@pagehub/sdk";
import "@pagehub/sdk/editor.css";
export default function Builder() {
return (
<PageHubEditor
callbacks={{
onLoad: async () => {
const res = await fetch("/api/pages/home");
return res.ok ? res.json() : null; // null = blank canvas
},
onSave: async (pageData) => {
await fetch("/api/pages/home", {
method: "PUT",
body: JSON.stringify(pageData),
});
},
}}
theme={{ primaryColor: "#2563eb" }}
/>
);
}SSR note: The editor uses browser APIs. In Next.js, load it with
next/dynamic:const Builder = dynamic(() => import("./Builder"), { ssr: false });
<div id="editor" style="height: 100vh"></div>
<script type="module">
import PageHub from "@pagehub/sdk";
import "@pagehub/sdk/editor.css";
const editor = PageHub.init({
container: "#editor",
callbacks: {
onLoad: async () => {
const res = await fetch("/api/pages/home");
return res.ok ? res.json() : null; // null = blank canvas
},
onSave: async (pageData) => {
await fetch("/api/pages/home", {
method: "PUT",
body: JSON.stringify(pageData),
});
},
},
});
</script>| Option | Type | Default | Description |
|---|---|---|---|
container |
string | HTMLElement |
— | DOM selector or element to mount into (vanilla JS only) |
apiKey |
string |
— | PageHub Cloud API key (optional for self-hosted) |
apiBaseUrl |
string |
"https://pagehub.dev/api" |
API base URL (override for self-hosted) |
pageId |
string |
— | Initial page ID to load |
readOnly |
boolean |
false |
Start in viewer mode |
callbacks |
PageHubCallbacks |
required | Your integration hooks (see below) |
theme |
PageHubTheme |
— | Visual theming |
features |
PageHubFeatures |
— | Feature toggles |
ai |
PageHubAIConfig |
— | AI generation config |
locale |
PageHubLocale |
— | Localization overrides |
The two required callbacks are how you connect PageHub to your backend:
callbacks: {
onLoad: (pageId?) => Promise<PageData | null>, // fetch page — return null for blank canvas
onSave: (pageData, meta?) => Promise<void>, // persist page
// Optional
onChange: (pageData) => void, // fires on every edit (debounced) — useful for autosave
onPublish: (pageData) => Promise<void>, // user clicked "Publish"
onMediaUpload: (file) => Promise<string>,// upload a file, return the public URL
onMediaDelete: (url) => Promise<void>, // delete a previously uploaded file
}The pageData object you receive on save:
{
content: string; // compressed editor state — store this to reload later
html?: string; // rendered static HTML — ready to publish
classes?: string[]; // Tailwind classes used — for CSS purging/compilation
title?: string;
seo?: PageSeo;
}theme: {
primaryColor: "#2563eb",
secondaryColor: "#7c3aed",
accentColor: "#06b6d4",
colorScheme: "system", // "light" | "dark" | "system"
logo: "/your-logo.svg", // shown in editor toolbar
cssVariables: { ... }, // custom CSS vars (no -- prefix needed)
customCSS: "...", // raw CSS injected into the editor
}Toggle editor capabilities on or off:
features: {
sidebar: true, // component panel
toolbar: true, // top toolbar
aiGeneration: false, // AI content generation (requires ai config)
multiPage: true, // multi-page site editing
responsivePreview: true, // device preview toggle
seoPanel: true, // SEO settings
importExport: false, // JSON import/export UI
customCSS: false, // CSS editor panel
restrictedComponents: [], // component names to hide from toolbox
}ai: {
enabled: true, // requires a PageHub account
}AI features (content generation, assistant) are powered by PageHub's API. Users can configure their own AI provider keys in their PageHub account settings.
PageHub.init() returns an instance with these methods:
const editor = PageHub.init({ ... });
// Save & load
editor.save({ isDraft: true });
editor.load("page-id");
editor.getPageData(); // { content, html, classes, ... }
// HTML export
editor.getHTML(); // rendered HTML string
editor.exportHTML({ // full static HTML + metadata
document: true, // wrap in <html><head>...</head><body>
title: "My Page",
includeThemeVars: true,
});
// JSON import/export
editor.exportJSON(); // raw CraftJS JSON string
editor.importJSON(jsonString); // load from JSON
// Runtime updates
editor.setReadOnly(true); // toggle viewer mode
editor.setTheme({ primaryColor: "#e11d48" });
editor.setFeatures({ sidebar: false });
// Events
const off = editor.on("save", (data) => console.log("Saved!", data));
off(); // unsubscribe
// Cleanup
editor.destroy();| Event | Payload | When |
|---|---|---|
ready |
— | Editor mounted and ready |
save |
PageData |
User or programmatic save |
load |
PageData |
Page loaded |
change |
PageData |
Editor state changed (debounced) |
publish |
PageData |
User published |
error |
Error |
Something went wrong |
modeChange |
"editor" | "viewer" |
Read-only toggled |
componentSelect |
node info | User selected a component |
componentDeselect |
— | Selection cleared |
Display saved pages in read-only mode — no editor UI, smaller bundle:
import { PageHubViewer } from "@pagehub/sdk/viewer";
<PageHubViewer content={savedContent} resolver={resolver} />The viewer injects Tailwind CSS at runtime — no stylesheet import needed.
Render pages to HTML on the server — no React, no browser required. Works in Node, edge workers, or build scripts:
import { renderToHTML } from "@pagehub/sdk/static-renderer";
// From compressed content (what onSave gives you)
const { html, classes, fontUrls } = renderToHTML(savedContent);
// From raw JSON
const { html } = renderToHTML(jsonString, { compressed: false });
// Full standalone document
const { html } = renderToHTML(savedContent, {
document: true,
title: "My Page",
});The SDK ships with these drag-and-drop components out of the box:
| Component | Description |
|---|---|
Container |
Flex/grid layout wrapper |
ContainerGroup |
Grouped layout sections |
Header |
Page header with nav |
Nav |
Navigation menu |
Footer |
Page footer |
Text |
Rich text with inline editing |
Image |
Responsive images |
ImageList |
Image gallery / grid |
Button |
CTA button with variants |
ButtonList |
Button group |
Video |
Video embed (YouTube, Vimeo, self-hosted) |
Audio |
Audio player |
Embed |
Raw HTML / iframe embed |
Form |
Form container |
FormElement |
Input, select, textarea, etc. |
Divider |
Horizontal rule |
Spacer |
Vertical spacing |
Background |
Full-bleed background section |
Pass additional components via the resolver:
<PageHubEditor resolver={{ ...defaultComponents, MyWidget }} />Or in vanilla JS:
PageHub.init({
resolver: { MyWidget },
// ...
});Import the editor stylesheet in your app:
import "@pagehub/sdk/editor.css";The SDK respects CSS variables for theming — dark/light mode works automatically.
Some editor features require a PageHub account or self-hosted backend:
| Feature | Requires Backend | Notes |
|---|---|---|
| Drag-and-drop editor | No | Works standalone |
| Viewer / static renderer | No | Works standalone |
| AI content generation | Yes | Enable with ai: { enabled: true }, requires PageHub account |
| Image uploads | Yes | Provide onMediaUpload callback or use PageHub CDN |
| Domain settings | Yes | Requires PageHub Cloud |
| Multi-tenant / user profiles | Yes | Requires PageHub Cloud |
The core editor and viewer work fully offline with just the onLoad/onSave callbacks.
Contributions are welcome! Please open an issue or pull request on GitHub.