Visual Page Builder

The Visual Page Builder lets you compose pages from a library of pre-built sections — hero banners, feature grids, testimonials, pricing tables, and more. Changes are saved back to the page's frontmatter as a sections: array, so the output is plain files like everything else in Dune.

When to use it

Use the Page Builder Use the block editor or TSX
Landing pages, marketing pages Blog posts, documentation
Pages composed of distinct visual sections Long-form prose content
Editors with no coding knowledge Developers building custom layouts
Drag-and-drop section reordering Fine-grained markdown formatting

Opening the builder

From any page in the admin panel, click Builder in the toolbar. The builder opens at /admin/pages/builder?path=….

To return to the classic block editor, click Classic Editor in the builder toolbar.

Builder UI

┌──────────────────────────────────────────────────────────────┐
│  ← Pages   Classic Editor   [page title]   🖥 📱 📲   Save  │
├────────────┬──────────────────────────────────┬──────────────┤
│ Sections   │  Canvas                          │ Page Settings│
│            │                                  │              │
│ 🚀 Hero    │  ┌─────────────────────────┐    │ Title        │
│ ✨ Features│  │ 🚀 Hero  #sec_abc  ▾ ↑↓⧉✕│    │ Slug         │
│ 💬 Testim. │  │   Headline              │    │ Date         │
│ 📣 CTA     │  │   Subtext               │    │ ☑ Published  │
│  …         │  │   CTA                   │    │              │
│            │  └─────────────────────────┘    │              │
│            │  ┌─────────────────────────┐    │              │
│            │  │ ✨ Features  #sec_def  ▾│    │              │
└────────────┴──────────────────────────────────┴──────────────┘

Left panel — Section palette. All available section types. Click a type to append it to the canvas, or drag it onto the canvas.

Center — Canvas. Your current sections in order. Each card shows the section type, its ID, and its fields when expanded. Use the arrow buttons (↑↓) to reorder, ⧉ to duplicate, ✕ to remove.

Right panel — Page settings. Title, slug, date, and published state for the page itself.

Toolbar. The preview buttons (🖥 📱 📲) resize the canvas to simulate desktop, tablet (768 px), and mobile (390 px) viewport widths.

Built-in sections

🚀 Hero

Full-width headline with optional subtext, background, and up to two CTA buttons.

Field Type Description
Headline text Main heading (required)
Subtext textarea Supporting paragraph
Primary CTA Label text Button text
Primary CTA URL url Button destination
Secondary CTA Label text Second button (optional)
Secondary CTA URL url Second button destination
Background select light / dark / brand
Background image URL image Optional full-bleed image

✨ Features

Icon + title + description cards in a responsive grid.

Field Type Description
Section Title text Heading above the grid
Subtitle textarea Optional sub-heading
Columns select 2 / 3 / 4
Features list Repeating items: icon (emoji), title, description

💬 Testimonials

Customer quotes with author attribution.

Field Type Description
Section Title text Heading above the quotes
Testimonials list Repeating items: quote, author, role, company, avatar URL

📣 Call to Action

Prominent band with headline, subtext, and a button.

Field Type Description
Headline text Required
Subtext textarea Supporting copy
Button Label text Required
Button URL url Required
Background select light / dark / brand

🖼️ Gallery

Image grid with optional captions.

Field Type Description
Section Title text Optional heading
Columns select 2 / 3 / 4
Images list Repeating items: image URL, caption, alt text

💰 Pricing

Side-by-side pricing plan cards.

Field Type Description
Section Title text e.g. "Simple Pricing"
Subtitle textarea e.g. "No hidden fees"
Plans list Repeating items: name, price, period, features (one per line), CTA label, CTA URL, highlighted (toggle)

The plan with highlighted checked gets a "Popular" badge and an accent border.

❓ FAQ

Accordion of questions and answers.

Field Type Description
Section Title text e.g. "Frequently Asked Questions"
Questions list Repeating items: question, answer

FAQ items are collapsible on the rendered page — click the + to expand.

📝 Rich Text

Free-form HTML block. Useful for content that doesn't fit other section types.

Field Type Description
Content richtext Raw HTML (required)
Width select narrow (640 px) / normal (800 px) / wide (full)

⬛ Columns

Two or three equal-width columns of HTML content.

Field Type Description
Column count select 2 or 3
Column 1 richtext HTML for first column
Column 2 richtext HTML for second column
Column 3 richtext HTML for third column (3-col only)

📬 Contact Info

Contact details with optional CTA button.

Field Type Description
Section Title text e.g. "Get in Touch"
Intro text textarea Optional paragraph
Email address text Shown with ✉️ icon
Phone number text Shown with 📞 icon
Address textarea Multi-line, shown with 📍 icon
Button Label text Optional CTA
Button URL url Optional CTA destination

How data is stored

The page file is a standard Dune markdown file. The builder writes layout: "page-builder" and a sections: array into the frontmatter:

---
title: "Product Landing Page"
layout: "page-builder"
published: true
sections:
  - id: sec_a1b2c3
    type: hero
    headline: "Ship faster with Dune"
    subtext: "The flat-file CMS built for developers and editors."
    cta_text: "Get Started"
    cta_url: "/getting-started"
    cta2_text: "View Demo"
    cta2_url: "/demo"
    background: dark

  - id: sec_d4e5f6
    type: features
    title: "Why Dune"
    columns: "3"
    items:
      - icon: "⚡"
        title: "Fast"
        description: "Sub-50 ms page delivery with built-in caching."
      - icon: "🔌"
        title: "Extensible"
        description: "Plugins, hooks, and a clean TypeScript API."
      - icon: "✍️"
        title: "Editor-friendly"
        description: "Block editor and visual page builder included."
---

You can edit this YAML directly in the Classic Editor if needed. The builder reads whatever is in the file when you open it.

Rendering

When Dune serves a page with layout: "page-builder", the routing layer calls renderSections() instead of rendering the markdown body. The output is self-contained HTML with embedded styles — it works without any special theme support.

Theme templates receive the sections HTML as their children prop, exactly like normal markdown content. The sections use CSS class names prefixed with pb- that themes can override for custom styling.

Custom sections (developer)

Custom section types can be registered at startup by calling sectionRegistry.register(def) from a plugin:

import { sectionRegistry } from "dune/sections";

sectionRegistry.register({
  type: "banner",
  label: "Announcement Banner",
  icon: "📢",
  description: "Highlighted message strip",
  fields: [
    { id: "message", type: "text", label: "Message", required: true },
    { id: "link_text", type: "text", label: "Link text" },
    { id: "link_url", type: "url", label: "Link URL" },
    {
      id: "color",
      type: "select",
      label: "Color",
      default: "blue",
      options: [
        { value: "blue", label: "Blue" },
        { value: "yellow", label: "Yellow" },
        { value: "red", label: "Red" },
      ],
    },
  ],
});

The new section type appears immediately in the builder palette. To control how it renders, add a case to a custom renderer or extend the built-in renderer in a plugin.

Tips

  • Reorder quickly: Use the ↑↓ buttons on each card or drag cards to a new position.
  • Duplicate a section: Click ⧉ to copy a section with all its field values — useful for similar pricing plans or repeated feature blocks.
  • Collapse cards: Click a card header to collapse it once you're done editing its fields. This keeps the canvas tidy on long pages.
  • Preview at breakpoints: Use the 🖥 📱 📲 toolbar buttons to check your layout at different widths before saving.
  • Mix with classic content: Pages that use the builder have an empty markdown body. If you switch back to the Classic Editor, the sections: frontmatter is preserved and you can edit it as YAML.