Skip to content

Creating Editable Areas

Summary

A practical guide for developers to define editable regions in templates and stand-alone articles, using the code editor (Monaco) with CKEditor-based Visual Editor.

How CKEditor Fits Into a Page

Before writing any markup, it helps to understand one fundamental constraint: CKEditor 5 edits HTML fragments, not full pages.

CKEditor is designed to own clearly bounded content regions — article bodies, text sections, structured rich text. It is not designed to control <html>, <head>, navigation, global chrome, or layout containers. Those parts of the page must exist outside the editor's reach.

In SkyCMS this means:

  • Editable regions are specific elements you explicitly mark in your layout or template HTML.
  • Everything outside those marked elements — the layout shell, header, footer, scripts — is never touched by the editor.
  • Editors interact only with the regions you define.

This boundary is enforced by the data-ccms-ceid attribute. Any element carrying that attribute becomes an editable region. Any element without it is invisible to CKEditor.

Quick Start (5 minutes)

  • Mark editable regions with data-ccms-ceid="my-id" (or data-ccms-new="true" for auto-GUID on first save).
  • Use block elements for rich content (e.g., div, section, article) and add class="ck-content" so CKEditor styles apply.
  • Use headings (h1–h6) or data-editor-config="title"/"heading" for minimal toolbar (no embeds/tables).
  • Use data-editor-config="simple", "standard", or "advanced" to explicitly control toolbar richness; omit the attribute for the standard default.
  • Use the image widget via data-editor-config="image-widget"; first image is typically treated as the page banner.
  • Do not nest editable regions; backend rejects nested regions.

Full page template skeleton

The following is the recommended starting structure when building a new layout or template. Non-editable zones carry contenteditable="false" so that browsers and screen readers cannot accidentally place focus inside them. Editable regions are isolated inside <main>.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>{{PageTitle}}</title>
  <link rel="stylesheet" href="/css/site.css" />
  <link rel="stylesheet" href="/css/content.css" />
</head>
<body>
<header contenteditable="false">
  <!-- Site navigation and global branding — never editor-managed -->
</header>
<main>
  <!-- Title region: minimal toolbar, heading-only -->
  <h1 data-ccms-ceid="page-title" data-editor-config="title">Page Title</h1>

  <!-- Body region: standard rich content -->
  <section data-ccms-ceid="body" class="ck-content">
    <p>Page body…</p>
  </section>
</main>
<footer contenteditable="false">
  <!-- Site footer — never editor-managed -->
</footer>
</body>
</html>

Key points:

  • contenteditable="false" on <header> and <footer> prevents the browser from making those zones accidentally focusable or editable.
  • Only elements with data-ccms-ceid are activated as editable regions.
  • There is no limit on how many editable regions a template can have, as long as none are nested inside each other.

Element Types & Toolbar Behavior

Use Case HTML Config/Classes Toolbar
Title/subtitle <h1>–<h6> or any block with data-editor-config="title"/"heading" data-ccms-ceid Minimal toolbar (bold/italic only)
Simple text any block data-ccms-ceid + data-editor-config="simple" + class="ck-content" Compact toolbar (basic formatting + links)
Standard content any block data-ccms-ceid + class="ck-content" Standard toolbar — default when data-editor-config is omitted
Advanced content any block data-ccms-ceid + data-editor-config="advanced" + class="ck-content" Full toolbar (images, media, tables, lists, code blocks, etc.)
Image widget <div data-editor-config="image-widget"> data-ccms-ceid or data-ccms-new + class="ck-content" FilePond-based upload UI

Notes: - ck-content keeps rendered content aligned with CKEditor’s CSS; avoid overriding its base rules. - Additional block tags are allowed; prefer semantic blocks for layout.

Required Data Attributes

  • data-ccms-ceid: Stable ID for the region. Use descriptive IDs when practical.
  • data-ccms-new="true": Auto-assigns a GUID on first save (shared generator across widgets/editors).
  • data-editor-config (optional): title or heading for minimal toolbar; simple, standard, or advanced to explicitly select toolbar richness; image-widget for image uploads. Omit for standard rich content (defaults to standard).
  • Optional for image widget: data-ccms-enable-alt-editor="true" to enable the alt/title modal per widget.

Examples

Rich body block:

<section data-ccms-ceid="body" class="ck-content">
  <p>Welcome to our product page.</p>
</section>

Title/subtitle:

<h1 data-ccms-ceid="page-title" data-editor-config="title">Product Name</h1>
<h2 data-ccms-ceid="page-subtitle" data-editor-config="heading">Great tagline goes here</h2>

Image widget (auto-ID on first save):

<div data-editor-config="image-widget" data-ccms-new="true" class="ck-content"></div>

Image widget with opt-in alt/title editor:

<div data-editor-config="image-widget"
     data-ccms-new="true"
     data-ccms-enable-alt-editor="true"
     class="ck-content"></div>

Rules & Conventions

  • No nesting: Do not place an editable element inside another; backend validation will reject it and nested regions may be removed.
  • Stable IDs: Keep data-ccms-ceid stable between template updates so content maps correctly.
  • Banner image convention: The first image uploaded on a page is treated as the banner image by convention.
  • Iframe context: Visual Editor runs inside an iframe; parent functions handle saving and autosave.
  • Autosave: CKEditor autosaves after ~1s idle when parent.enableAutoSave is true.

Styling Guidance

  • Apply ck-content to non-title editable areas so CKEditor’s content CSS (ckeditor5-content.css) styles lists, tables, images, etc.
  • Avoid overriding .ck-content base rules; layer your component/page classes instead.
  • Headings with minimal toolbar do not require ck-content, but can have it if you need consistent typography.

Image Widget Highlights

  • Uses FilePond uploads; supports drag/drop, replace, library browsing, delete.
  • Upload path: /pub/articles/{articleNumber}/ when articleNumber is available; otherwise /pub/images/.
  • Alt/Title modal is enabled per widget via data-ccms-enable-alt-editor="true"; global toggle via CCMS_IMAGE_WIDGET_CONFIG.enableAltTextEditor.
  • Emits custom events via window.CCMSImageWidgetEvents (imageChanged with { type, id, element, imageSrc }).

Duplicator Pattern (Reusable Blocks)

Use the duplicator to clone repeatable sections (e.g., cards, FAQs, feature rows):

  • Wrap repeatable items with classes/components the duplicator expects (see Editor/wwwroot/lib/cosmos/dublicator/dublicator.js).
  • Each cloned child should contain editable elements with data-ccms-ceid (or data-ccms-new).
  • On clone, editors/widgets are re-initialized; on delete, editors/widgets are torn down to save the page body cleanly.
  • New clones automatically get fresh data-ccms-ceid values to avoid ID collisions; avoid nesting editable regions inside each other.

Minimal pattern example:

<div class="ccms-clone" data-ccms-ceid="feature-1">
  <h3 data-ccms-ceid="feature-1-title" data-editor-config="heading">Fast</h3>
  <div data-ccms-ceid="feature-1-body" class="ck-content">Our platform is fast.</div>
</div>
Then call Duplicator.create(element) on each clone container in script.

What Gets Stored

SkyCMS stores only the inner HTML of each editable region — not the surrounding element, not class="ck-content", not any wrapper markup.

For example, if the template contains:

<section data-ccms-ceid="body" class="ck-content">
  <p>Welcome.</p>
</section>

What is saved to the database for the body region is:

<p>Welcome.</p>

At render time, SkyCMS places that saved fragment back inside the .ck-content element. This means:

  • The wrapping element and its attributes come from the template or layout, not from stored content.
  • Changing the wrapper element (for example from <section> to <div>) in a template update has no effect on the saved content — it just changes the container.
  • Never store or pass the outer .ck-content element as the content payload; only the inner HTML belongs in storage.

Troubleshooting

  • Editable regions missing in Visual Editor: Check for data-ccms-ceid (or data-ccms-new) and ensure no nesting.
  • Content lost after template update: IDs changed or regions removed; keep IDs stable.
  • Toolbar too minimal: Remove data-editor-config="title"/"heading" or switch to a non-heading block for rich content.
  • Image widget not initializing: Ensure data-editor-config="image-widget" and that FilePond scripts are loaded.
  • Styling looks off: Confirm class="ck-content" on rich areas and avoid overriding CKEditor base styles.

See Also