Skip to Content

CMS

Hyperclay has a built-in CMS that turns any page into something a non-technical person can edit. You describe what counts as content with a single tag, add one button, and clicking it slides in an editing sidebar. As the editor types, the changes are written straight back into the page, and saving the page writes them into the file. There is no database, no admin backend, and no separate content store. The page is the content.

The mental model is a two-way loop with the page as the source of truth. The CMS reads a JSON object out of your page using rules you define, builds a form bound to that object, and writes every edit back onto the page as you make it.

Turn it on

The CMS ships in the smooth-sailing and everything presets of HyperclayJS, so on most apps it is already loaded. Use one of those presets:

<script src="https://cdn.jsdelivr.net/npm/hyperclayjs@latest/src/hyperclay.js?preset=smooth-sailing" type="module"></script>

If you build a custom feature list instead of a preset, add &features=hypercms.

Describe your content

Add one rules tag to the page. It is a small JSON map from a field name to a CSS selector, and it tells the CMS what on the page is editable.

<h1 class="title">My Site</h1> <p class="tagline">The tagline goes here</p> <script data-rules-name="cms" data-rules-version="1" type="application/json"> { "title": ".title", "tagline": ".tagline" } </script>

data-rules-version must be "1". The selector grammar is small:

RuleReads / writes
".title"the element’s text
".price@data-cents"an attribute or property
"img@src", "a@href"attributes
".agree@checked"a checkbox
".tag[]"a list of plain values (a scalar array)
[".post", { "heading": ".post-title" }]a list of cards (an object array)
{ "author": { "name": ".name" } }a nested group

Open the editor

Add a button that calls open(). The CMS builds the form from your rules and mounts it as a sidebar.

<button onclick="hyperclay.hypercms.open()">Edit content</button>

That is the entire integration. Every field in your rules becomes an input, and editing it updates the page live.

Editable lists

For a list of repeating items, use the [selector, shape] form. The editor gets add, remove, and drag-to-reorder controls automatically.

<ul class="posts"> <li class="post"> <h3 class="post-title">First post</h3> <p class="post-body">Hello world.</p> </li> </ul> <script data-rules-name="cms" data-rules-version="1" type="application/json"> { "posts": [".post", { "heading": ".post-title", "body": ".post-body" }] } </script>

So a list can grow from empty, mark a hidden seed element with cms-template. The CMS ignores it when reading and writing data, and clones it when the editor adds the first item.

<ul class="posts"> <li class="post" cms-template hidden> <h3 class="post-title"></h3> <p class="post-body"></p> </li> </ul>

Saving, and what gets saved

This is the important part. The CMS only changes the live page. It never saves on its own. You save the page the normal Hyperclay way, with Cmd+S or autosave, and that writes the current DOM into the .html file.

The sidebar itself is never part of the saved file. It marks itself so the save system skips it, and the editing state is stripped on the way out, so the file on disk only ever contains your content. Open the saved file anywhere and it is just clean HTML with your latest edits baked in.

Undo and live editing come for free

Because the CMS edits the real page, the rest of the platform cooperates with it automatically:

  • Undo works on CMS edits. Each add, remove, and reorder is a labeled, undoable step, and Cmd+Z steps back through them. See Undo and Redo.
  • Live-sync keeps the form fresh. If the page changes from another device or collaborator, the sidebar re-syncs to match, and it preserves whatever field you are currently typing in.

Customize the form

The default inputs are generated for you, so you usually write no form markup at all. When you want control over how a field or a card renders, add a <template> keyed to it:

<template data-hcms-tpl="posts"> <div class="hcms-card"> <div class="hcms-card-fields"></div> <button data-hcms-action="remove">Delete post</button> </div> </template>

Inside a template, mark the slots the CMS fills: data-hcms-field, data-hcms-label, and data-hcms-action="add | remove | move-up | move-down", plus .hcms-card-fields for an object array. Constrain a list with attributes on the template:

AttributeEffect
data-hcms-min-items="1"hide remove at the floor
data-hcms-max-items="10"hide add at the ceiling
data-hcms-no-addno add button
data-hcms-no-removeno remove button
data-hcms-no-reorderno drag handles

Your own custom inputs (a rich text widget, a color picker) work with no CMS API: drop the element inside a template and your existing init code wakes it up. The CMS only moves text and attributes in and out of the DOM, it does not need to know the element is special.

Outside Hyperclay

The CMS is also a standalone package, @panphora/hyper-cms. Its one hard dependency is HyperclayJS’s Mutation utility, which is present whenever you load HyperclayJS.

import { cms } from '@panphora/hyper-cms' cms.open()

Outside a Hyperclay app there is no automatic save, so persisting the edited HTML is up to you.

Last updated on