Visual Page Builder
Editors build pages by arranging components in Drupal Canvas, and the preview they see is your real frontend. The components are the ones your developers wrote in Next.js or Astro; Canvas only stores which ones are on the page and what they say.
Overview
The visual page builder gives marketers and content editors a no-code way to create and edit landing pages. Developers set up the components once, and editors mix, match and fill them in without touching code.
Key features:
- A component library that comes from your frontend, so it never drifts from what the site can render
- Live preview rendered by your own Next.js or Astro app, including unsaved changes
- Draft and publish: visitors only see a change after it is published
- Nested components, such as cards inside a card group or tiers inside a pricing section
- Images from the Drupal media library
- Page title, URL alias and SEO fields alongside the layout
Quick Start
Both starters ship with the editor wired up: Decoupled Components (Next.js) and Decoupled Components (Astro).
- Create a space in the dashboard and choose one of the starters as its frontend.
- Open Canvas from your Drupal site (
/canvas). - Pick a page, or create a new one from the page menu at the top.
- Insert components from the library on the left, and edit their fields on the right.
- Click Review changes, then Publish.
How It Works
Architecture
Drupal (CMS) Your frontend (Next.js or Astro)
├── Canvas editor (/canvas) ├── /[...slug] ← Pages
├── Canvas pages ├── /api/canvas/components ← Component library
│ └── component tree ├── /api/draft ← Start a draft session
├── Content API └── canvas/<name>/
│ └── /canvas/content-api ├── component.yml ← Fields and slots
└── Media library └── index.tsx | .astro ← The component
- The library comes from the frontend. Each component is a folder with a
component.yml(its fields and slots) and its implementation. When an editor opens Canvas, it reads the list from your app, so adding a component is a frontend change only. - Pages are stored as a component tree. Drupal keeps one list per page: which components, in which order, nested in which slot, with which field values.
- The frontend renders the tree. Your app asks Drupal's content API for a path and renders the components it gets back.
Editing Flow
- The editor opens a page in Canvas. Canvas loads your frontend in a preview frame.
- Drupal hands the frontend a short-lived, single-use signed token for that editor. The frontend exchanges it for a read-only draft session.
- Every change is auto-saved as a draft, and the preview reloads with it. Visitors still see the published version.
- Publish makes the draft live. The frontend is told to revalidate the page.
Draft preview works in Chromium-based browsers. It relies on a partitioned cookie inside the preview frame, which Safari 18.5 to 26.1 does not support.
Available Components
| Component | Description | Nested items |
|---|---|---|
| Hero | Full-width header with gradient or image background and two buttons | — |
| Card Group | Feature cards in a 2 to 4 column grid | Cards (icon, title, description, link) |
| Side by Side | Image next to content with a feature list | Feature items (icon, title, description) |
| Text Block | Rich text with an optional button | — |
| Stats | Key metrics | Stat items (value, label, description) |
| Testimonials | Customer quotes in a grid or single layout | Testimonials (quote, author, photo, rating) |
| Logo Collection | Client or partner logos | Logos (name, image, link) |
| Pricing | Pricing tiers side by side | Pricing tiers (name, price, features, button) |
| Accordion | Collapsible questions and answers | FAQ items (question, answer) |
| Newsletter | Email signup on a dark, light or gradient background | — |
Nested items are components in their own right. Editors add as many as they want into the parent's slot and reorder them by dragging.
Adding a Component
- Create a folder in your starter's Canvas directory:
canvas/<name>/in Next.js,src/canvas/<name>/in Astro. - Add a
component.ymldescribing its fields and slots:
name: Call to Action
machineName: call_to_action
status: true
required:
- title
props:
properties:
title:
title: Title
type: string
examples:
- Ready to get started?
buttonText:
title: Button text
type: string
buttonUrl:
title: Button link
type: string
format: uri-reference
slots: {}
- Add the implementation next to it:
index.tsxfor Next.js,index.astrofor Astro. It receives the fields as props and each slot as children. - Reload Canvas. The new component appears in the library.
Field types map as follows:
component.yml |
Editor field |
|---|---|
type: string |
Text input |
type: string with enum |
Select list |
type: string with contentMediaType: text/html |
Rich text |
type: string with format: uri-reference |
Link |
type: boolean |
Checkbox |
type: integer |
Number |
$ref: json-schema-definitions://canvas.module/image |
Media library image |
If one Drupal site serves both starters, keep their component.yml files identical. Canvas refuses to sync a component whose definition differs between two frontends. Each starter has npm run check:canvas for this.
Adding the Editor to an Existing Project
The starters are the quickest route. To wire up your own frontend:
- Install the adapter for your framework:
@drupal-canvas/headless-nextor@drupal-canvas/headless-astro. - Add a
canvas.config.jsonpointing at your component directory. - Mount the adapter's draft routes and component endpoint, and render pages with its component tree renderer. The starters are the reference implementation.
- Set
CANVAS_SITE_URLto your Drupal site URL. - Register your frontend in Canvas under Headless frontends.
Drupal Side
Spaces include Drupal Canvas with its headless integration, plus a small Decoupled.io module that:
- registers your frontend with Canvas when you connect it in the dashboard
- syncs the component library without an editor having to open Canvas first
- imports the starter's sample content as Canvas pages
- revalidates the frontend when a page is published