Skip to Content
Strapi Page Builder 1.2 is now available 🎉

<Editor /> Component

app/editor/page.tsx
import { Editor } from "@wecre8websites/strapi-page-builder-react"; import "@wecre8websites/strapi-page-builder-react/editor.css" import { notFound } from "next/navigation"; import config from "../../blocks/PageBuilderConfig"; const strapiConfig = { url: process.env.NEXT_PUBLIC_API_URL as string, authToken: process.env.STRAPI_ADMIN_TOKEN as string, imageUrl: process.env.NEXT_PUBLIC_IMAGE_URL as string, } export default async function EditorPage({ searchParams }: { searchParams: Promise<{ _pagebuilderToken?: string }> }) { const { _pagebuilderToken } = await searchParams; if (!_pagebuilderToken) return notFound(); return <Editor config={config} apiKey={process.env.PAGE_BUILDER_API_KEY as string} strapi={strapiConfig} allowedParentOrigin="https://cms.example.com" /> }

Use <Editor /> from a Server Component. There it keeps apiKey and strapi.authToken on the server (see Security). If you wrap it in your own "use client" component, or render it in a client-only app, those values are sent to the browser.

Props

ParameterDescriptionRequired
apiKeyThe API key for the Strapi Page Builder. Sign up for free. Server-only: never sent to the browser.true
configThe configuration object for the Strapi Page Builder. See Editor Configuration.true
strapiThe configuration object for Strapi.false
allowedParentOriginThe origin of your Strapi admin, e.g. https://cms.example.com. When set, the editor only talks to that origin. Recommended in production, together with a frame-ancestors header. See Security.false
contentKeyIf set, the entry being edited is exposed to components as metadata[contentKey] instead of at the top level.false
additionalContentExtra data merged into the content available to components (for example a dictionary or navigation). Kept on the server until the editor token is validated.false
resolveLinkA Server Action  (path, locale) => { contentType, contentId, templateId?, locale? } | null. Called when a link is followed in the preview; return the Strapi entry that page is built from and the editor opens it. See Links in the preview.false
fetchA Server Action  (contentId) => content used to load the entry yourself instead of using the data from Strapi. Its id is public, so it must check permissions itself.false

Strapi Configuration Object

ParameterDescriptionRequired
urlThe URL of the Strapi API.true
authTokenA Strapi API token, used on the server to load content for previews. A Read-Only token is enough. Never sent to the browser.false
imageUrlThe URL of the image server. Required if using the media field typefalse

How the editor is protected

  • The editor token that Strapi puts in the iframe URL is checked on the server, with your API key, before any content is shown. Invalid, expired or missing tokens show an error and nothing else.
  • Content lookups made while editing go through a server action that needs the validated session, so the Strapi token is never used by the browser.
  • The editor ignores messages from any window except its direct parent, and only after validation.

Links inside the editor preview never navigate the editor away from your Strapi admin:

  • External links (other sites, mailto:, tel:) do nothing, whichever way they are opened (click, ctrl/cmd-click, middle-click).
  • In-page anchors (#section) scroll the preview to the target.
  • Internal links (same site) do nothing unless you provide resolveLink. With it, the editor asks your site which Strapi entry the path belongs to and opens that entry, updating the address of the Strapi admin page so you can bookmark or reload it. If you have unsaved changes the editor asks before leaving.
app/editor/page.tsx
async function resolveLink(path: string, locale?: string) { "use server"; const entry = await findEntryByPath(path); // your own lookup if (!entry) return null; // unknown paths are ignored return { contentType: "api::page.page", // the content type's uid contentId: entry.documentId, templateId: entry.template?.documentId, // recommended: the template the entry uses locale: entry.locale, }; } <Editor config={config} apiKey={...} strapi={...} resolveLink={resolveLink} />

Like the fetch prop, a Server Action’s id is public, so resolveLink should only return what the editor is allowed to open.

Last updated on