---
title: The Visual Page Builder
description: "The visual builder is a drag-and-drop editor built into the page editor. Use it for landing pages, feature pages and anything where layout matters; use the rich-text editor for prose such as terms and policies. This article is for operators…"
url: "https://rackhelm.com/documentation/visual-page-builder/"
updated: "2026-09-24"
category: "Content, Storefront & Marketing"
---

# The Visual Page Builder

The visual builder is a drag-and-drop editor built into the page editor. Use it for landing pages, feature pages and anything where layout matters; use the rich-text editor for prose such as terms and policies. This article is for operators and assumes you have already read [Content Pages](/docs/content-pages/).

## Before you start

> **Note:** The builder is part of the page editor, so it needs the `manage_pages` permission. Image uploads are written to the public storage disk, which requires the storage symlink created during installation.

## Choosing an editor

At the top right of the **Content** box there are two buttons: **Rich text** and **Visual builder**. New pages open in the visual builder; the seeded legal templates are prose and open in rich text.

You can switch at any time, but the two store different things:

- A rich-text page is a single block of formatted markup.
- A built page is markup *plus* its own stylesheet, plus the builder's project data.

Switching a built page to rich text and saving flattens the visual layout. RackHelm warns you before you do it, and it keeps the stylesheet and the project data on the record, so switching back restores the design. Anything you type in rich text in the meantime is lost when you switch back.

![The page editor with the visual builder open, showing the block palette, canvas and style manager](/wp-content/uploads/rackhelm-docs/content-page-builder-canvas.png)
With the visual builder active the editor takes the full width and the settings sidebar drops below the canvas.

## Building a page

1. Drag blocks from the palette on the right into the canvas — sections, columns, text, images, buttons, flexbox rows, a navbar and tabs are all included.
2. Select an element to style it. The canvas loads the site's own stylesheet, so Bootstrap classes look the same in the editor as on the finished page.
3. Use `/page-link/{slug}` as the URL of any link that points at another content page — it survives a group or slug rename.
4. Select **Create Page** or **Update Page**. The builder writes its markup, its stylesheet and its project data into the form as it submits.

> **Tip:** A built page renders without the prose chrome — no breadcrumb, no card, no reading-width column — so full-width sections really do reach the edge of the window.

### Dynamic blocks stay live

A visual builder stores a snapshot, which is the wrong shape for anything that has to stay current. Blocks in the **Dynamic** category are different: the builder drops a marker in the page, and RackHelm renders the real thing on every view.

The block shipped today is **Product pricing grid** — "the most-subscribed products from one store group, with live prices". It takes two options, written into the block's `data-rh-opt` attribute as `group=Web hosting;limit=3`:

| Option | What it does |
| --- | --- |
| `group` | The name of the store product group to pull from. Default `Web hosting`. It must match the group name exactly. |
| `limit` | How many products to show. Default `3`; clamped to between 1 and 6 when rendered. |

In the canvas the block appears as a dashed blue placeholder. Products are ordered by how many active services each one has, and the middle card is flagged "Most Popular". Only products that are active and included in the store are eligible.

![The dashed blue Dynamic block placeholder for the product pricing grid inside the builder canvas](/wp-content/uploads/rackhelm-docs/content-page-builder-dynamic-block.png)
Dynamic blocks show as a dashed placeholder while you edit and are filled in from your catalogue when the page is viewed.

## Images and other assets

Open the builder's asset manager (double-click an image component) and drop files in to upload them. The rules are enforced server-side:

| Limit | Value |
| --- | --- |
| Formats accepted | JPEG, PNG, GIF and WebP |
| Maximum file size | 5,120 KB (5 MB) per image |
| Files per upload | 20 |
| Stored at | the public disk under `pages/assets`, served from `/storage/pages/assets/…` |

> **Warning:** SVG uploads are deliberately rejected. An SVG can carry script, and these files are served from your portal's own domain.

## What the builder is allowed to produce

Everything you save is cleaned on the way into the database and again on the way out. Knowing what survives saves you a puzzling afternoon:

- **Markup** — structural HTML with `class` and `id` attributes. `<script>`, `<style>`, `<link>`, `<base>`, `<form>` and every `on…` event attribute are removed.
- **Embeds** — an `<iframe>` is kept only when its address starts with `www.youtube.com/embed/`, `www.youtube-nocookie.com/embed/`, `player.vimeo.com/video/` or `www.google.com/maps/embed`. Anything else is dropped. The builder's own Video and Map blocks are removed from the palette for the same reason.
- **Styles** — layout is kept in the page's stylesheet, and modern properties (flexbox, grid, gradients, shadows, transforms) are supported. Inline `style` attributes are lifted into that stylesheet automatically.
- **Scope** — the stylesheet is confined to the page's own canvas element when rendered, so a page can never restyle the site header, navigation or footer. Element ids are given an `rhp-` prefix so a page cannot collide with the application's own ids.

Size caps: the markup may be up to 512,000 characters, the stylesheet up to 256,000, and the builder's project data up to 2,000,000. A page that large is a mistake rather than a design.

## How the page is served

The cleaned markup and the scoped stylesheet are cached for a day, keyed on a fingerprint of the page body — so any edit, including one made directly in the database, invalidates the cache by itself. Dynamic blocks are never cached: they are rendered on every request so prices are always current.

## Troubleshooting

| Symptom | Cause and fix |
| --- | --- |
| "The visual editor did not load" | The editor scripts failed to initialise. Reload the page, or switch to rich text. The form refuses to submit in this state, because saving would blank the page body. |
| Classes and layout vanished after saving | The page was saved in rich-text mode. Switch back to the visual builder — the stored design is restored — and save again from there. |
| An embedded video or map shows nothing | Only YouTube, Vimeo and Google Maps embed URLs are kept. Re-add the embed with one of those URLs. |
| The pricing block shows "No hosting packages are currently available." | The `group` option does not match a product group name, or that group has no active, in-store products. |
| An image upload is rejected | It is over 5 MB, is an unsupported format, or you sent more than 20 files at once. |
| Uploaded images 404 on the public page | The public storage symlink is missing. Recreate it with `php artisan storage:link`. |
| A web font or external script never loads | The portal's content security policy only allows assets served from your own domain. Host the file with the portal instead of loading it from a CDN. |
