Best practices for HTML elements in rich text

Last modified: June 21st, 2023

Working with a specific static site generator?
Customize CloudCannon's documentation to suit your SSG.

Great! We'll show you documentation relevant to .
You can change this any time using the dropdown in the navigation bar.

For the purposes of this article, rich text content is any HTML or Markdown content that can be edited in CloudCannon. Custom markup is any HTML or Markdown structure that cannot normally be produced in CloudCannon's WYSIWYG editor (for example, HTML elements like <footer> or data attributes).

If you want to include custom markup in your rich text content, there are some limitations you should be aware of.

HTML that cannot be reconstructed#

We don't recommend custom markup inside rich text content. The rich text editor cannot produce visible and unambiguous representations of any arbitrary markup, and your team might be unable to see the underlying structures. This means you can accidentally delete custom markup without noticing, and you won't be able to restore it without going back to the source code.

Templating code also falls within this category, since it cannot be properly represented, edited, or reconstructed within the editor.

HTML that cannot be rendered#

To prevent cross-site scripting attacks and other unwanted interactions between your code and the editing interface, some HTML elements will not be rendered normally in the rich text editor. These elements will be replaced with boxes, which you can edit around without worrying about the original HTML being altered.

script and style elements replaced with boxes

Some elements with simple text content, like kbd and main, will be included in this process and will become uneditable. These elements always also fall into the category of HTML that cannot be reconstructed, and should be avoided in rich text content anyway.

The full list of elements that will be replaced with boxes is: base, blink, button, canvas, data, datalist, dfn, dialog, fieldset, form, hgroup, iframe, input, kbd, label, legend, link, main, map, marquee, math, menu, menuitem, meta, meter, noscript, object, optgroup, option, output, picture, portal, progress, q, rb, rp, rt, ruby, samp, script, select, slot, source, style, svg, template, textarea, time, title, track, var, and wbr.

Any content that is not boxed this way will also be processed with a sanitization library, to remove potential vulnerabilities or clashes with the CloudCannon interface. This will remove most attributes from HTML elements. The only exceptions are the class attribute, and other basic attributes required for the functionality of different elements (e.g. src and alt for img). Once again, these attributes also fall into the category of HTML that cannot be reconstructed, and should be avoided in rich text content anyway.

Best practices#

The simplest approach is to ensure that all markup in your rich text content can be rendered and edited in CloudCannon. Any markup that can be straightforwardly converted between HTML and Markdown is most likely okay.

If you need custom markup in your rich text content, configure snippets to provide a safe, structured way to edit that content.


It's important to think about the kind of markup that goes into rich text content. Any custom markup is subject to be removed by either of the processes described in this article. Let's look at an example, and how to solve this problem.

In the following example, we have added a heading with an id attribute to our rich text, with the goal of being able to link directly to that heading from elsewhere.

<h1 id="introduction">Introduction</h1>

Blog post content goes here.

However, we have now added an HTML structure that cannot be reproduced in CloudCannon's rich text editor. If a team member deletes this heading, they won't be able to add the id attribute if they need to recreate it. There is also no visual representation of the id attribute, so it's likely that no one will notice it is broken for a while. Even if this doesn't happen, CloudCannon's sanitization process will remove the id attribute when the element is loaded in the editor.

Solutions to this problems might include:

  • Configuring snippets to replace your custom markup. Read more about configuring snippets with Hugo, Eleventy, and MDX.
  • Use postprocessing to add the desired HTML during the build (for example, using Hugo's Markdown render hooks).
Open in a new tab