@drupal-canvas/headless-next
v0.5.0
Published
Next.js adapter for the Drupal Canvas Headless SDK.
Readme
@drupal-canvas/headless-next
Next.js adapter for the Drupal Canvas Headless SDK.
It gives a Next.js app draft preview bound to the editing user, in-place session renewal inside the Canvas editor frame, and the component metadata endpoint Drupal Canvas registers the app's components from.
Installation
npm install @drupal-canvas/headless-nextSet the CANVAS_SITE_URL environment variable to your Drupal site URL.
Usage
1. next.config.ts — the config wrapper generates the component manifest at
build time and sends a session-aware CSP frame-ancestors header:
import { withCanvas } from '@drupal-canvas/headless-next/config';
export default withCanvas();2. Route files — mount the handlers, one file per route:
// app/api/draft/route.ts
import { createDraftRouteHandlers } from '@drupal-canvas/headless-next';
export const GET = createDraftRouteHandlers().draft.GET;// app/api/draft/renew/route.ts
import { createDraftRouteHandlers } from '@drupal-canvas/headless-next';
export const POST = createDraftRouteHandlers().draftRenew.POST;// app/api/disable-draft/route.ts
import { createDraftRouteHandlers } from '@drupal-canvas/headless-next';
export const POST = createDraftRouteHandlers().disableDraft.POST;// app/api/canvas/components/route.ts
import { createComponentMetadataHandler } from '@drupal-canvas/headless-next';
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
export const { GET, OPTIONS } = createComponentMetadataHandler();// app/api/canvas/component-preview/page.tsx
export { default } from '@drupal-canvas/headless-next/ComponentPreviewPage';3. Session banner — a server component gathers the session state
(getDraftData(), getDraftEditorOrigin(), isDraftSessionExpired()) and
renders <DraftSession> from @drupal-canvas/headless-next/client with a
render prop that owns the banner markup.
4. Component tree — pass the structured content returned by fetchPage() to
<CanvasComponentTree>:
import { CanvasComponentTree } from '@drupal-canvas/headless-next/CanvasComponentTree';
<CanvasComponentTree tree={page.content} />;withCanvas() generates a registry of every discovered component
implementation, and the renderer consumes it automatically. During development
the registry updates when components are added, removed, or renamed.
Data access
getClient() returns the draft-aware JSON:API client; fetchPage() fetches
Canvas-rendered content when available, plus route and document-head data, for a
path resolved through Drupal routing. Both are draft-session-aware. Render
page.content directly. Use toNextMetadata(page.head) from
@drupal-canvas/headless-next in generateMetadata(). Handle PageRedirect
before page rendering with permanentRedirect() for permanent redirects and
redirect() for other redirects.
The client's JSON:API prefix is resolved from the site's public site-data
endpoint (fetched once per server instance), so sites serving JSON:API from a
non-default prefix (e.g. /api) work without configuration. When that endpoint
is unreachable, the CANVAS_JSONAPI_PREFIX environment variable applies, then
the /jsonapi default. getPublicClient() and getDraftClient() are async for
the same reason: await them like getClient(). For full manual control, use
JsonApiClient from @drupal-api-client/json-api-client directly.
fetchEntity({ type, id, viewMode }) renders one content entity without
page-level route or head data. Use it for embedded renders such as teaser cards.
toNextMetadata() maps the Canvas head entries that Next.js Metadata can
represent. It omits entries that Next.js Metadata cannot represent. Render
omitted entries as native head elements in the page or layout.
