Block Editor

Last Updated: Sep 6, 2022
documentation for the dotCMS Content Management System

The Block Editor field in dotCMS is a new rich content editor that allows you to create your content as building blocks.

Every element inside your editor is a block that you can add, edit, drag, and drop to reorder and delete.

Block Types

Block types currently include the following:

BlockSystem Name(s)Description
ParagraphparagraphDefault block type, for text and formatting marks
Headingheading1
heading2

heading6
Various levels of section headings
ListbulletList
orderedList
listItem
Ordered or unordered lists, and the items thereof
Block QuoteblockQuoteFor paragraph-length quotations
Code BlockcodeBlockMonospaced preformatted section
Horizontal LinehorizontalRuleA line for dividing vertical sections
ImagedotImageFully compatible with copy/paste or drag & drop insertion, image blocks are stored as dotAssets
ContentletcontentletsSpecial blocks consisting of Content Type instances defined elsewhere in dotCMS, allowing for the creation of rich and dynamic content

Block Formatting

Apply marks to text with the Block Editor's text menu.

You can style your blocks with bold, italic, underline, and strikeout marks.

You can alter the alignment of blocks or transform them into other blocks. A paragraph can be turned into a heading, a blockquote, and so on, with a just a simple dropdown selection.

Field Variables

Screenshot of several example field variable settings.

Styling

When defining a Block Editor field inside a Content Type, you can define its CSS styling by way of a field variable. Simply add a field variable with the key styles and set its value equal to a CSS string containing the desired settings, separated by semicolons.

Limiting Available Blocks

It may be useful or necessary in some cases to limit the blocks that a user can add to a given Block Editor Field. For example, typically the h1 tag is occupied by the page or article title, and thus an h1 is not needed on a given blog post.

To limit the available blocks, create a whitelist with the allowedBlocks field variable, which accepts a comma-separated list of block system names, as detailed in the table above — such as heading2,heading3,paragraph.

Limiting Available Contentlets

Similar to whitelisting block types, it is possible to limit the available Content Types available for insertion into the Block Editor as contentlets. Use the key contentTypes, and set the value to a comma-separated list of Content Type variables.

JSON Object

The block content gets saved as a JSON object with all the information you need to render it in your page. For example, say your Block Editor's content consists of a single paragraph containing “Hello World”; its final object would look like this:

{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "marks": [
            {
              "type": "bold"
            }
          ],
          "text": "Hello"
        },
        {
          "type": "text",
          "text": " World"
        }
      ]
    }
  ]
}

Each block object has two important properties:

  1. type: a string with the name of the block
  2. content: an array of blocks containing the content

The JSON output always begins with a type of doc, which is the parent block. The content property contains all the child-block data — i.e., the content itself.

Within the content blocks, there are further conventions to note, the most important of which is the distinction between text and non-text block types.

The text Type

A content type of text specifies the raw text of the block. For example, a heading, paragraph, or blockquote block will contain content of type text. These members may additionally contain a property named marks, which contain formatting information: bold, italic, underline, etc.

Non-Text Types

Other blocks, such as image or contentlet blocks, will store in their content all the properties necessary to render them. For an image block, this includes its path, width, and height; for a contentlet, it will have all the information about the contentlet field, including the iNode, identifier, etc.

Rendering Content

VTL Rendering

To render a Block Editor field from within a container, call the toHtml() velocity method on the contentlet object:

$dotContentMap.blockFieldName.toHtml()

This will render the content of the field into basic HTML.

For example:

  • Paragraphs: <p>Content</p>
  • Headings:
    • <h1>Content</h1>
    • <h2>Content</h2>
    • <h3>Content</h3>
  • List: <ul><li>Content</li></ul>
    • Ordered <ol><li>Content</li></ol>
    • Unordered <ul><li>Content</li></ul>
  • Horizontal Line: <hr>

Customizing Block HTML Rendering

dotCMS permits customization of how blocks are rendered as HTML. Simply create VTL files named for the block they override, and then define the rendering behavior within.

For a list of these names, see the “System Name” column of the table under Block Types). Additionally, there are two other overridable type names:

  • text — described under The text Type
  • hardBreak — allows the override of line-break behavior.

Finally, call the toHtml() method, passing as an argument the path to the folder containing the overriding file or files.

Customization Example: Heading 1

To modify the Heading 1 blocks, first create a file named heading1.vtl inside the /application/storyblock folder.

Add the following code to the file:

#parse( "static/storyblock/marks-macro.vtl" )
<h1 class="text-heading">
    #foreach($content in $item.content)
        #renderText($content)
    #end
</h1>

In this code:

  1. We import the macros.
  2. We add the HTML <h1> tag with any class or attributes we need.
  3. In the foreach, we iterate over all the items inside the content and render the text using the renderText macro that will handle formatting marks automatically.

Finally, update your container code to pass the folder with the VTL you created to the toHtml() method like this:

$content.blockFieldName.toHtml('/application/storyblock/')

dotCMS will look for VTL files for each block in the storyblock folder and fall back to the default rendering behavior if no custom file is found.

Headless Rendering

Headless rendering of the Block Editor begins with an API call to fetch the JSON object. This call may be made via a variety of APIs, including the Page API, GraphQL, Content API, Elasticsearch API, or any other API capable of calling a contentlet containing a Block Editor field.

For example, a Page API call would be a straightforward retrieval using this address template:

https://{server_address}/api/v1/page/json/{page_path}

Below is a demo page and its corresponding Page API path. Please note that the Page API requires being signed in (user:admin@dotcms.com, password:admin):

…/blog/post/french-polynesia-everything-you-need-to-know /api/v1/page/json/blog/post/french-polynesia-everything-you-need-to-know

On the linked page's output, the blogContent field begins as all Block Editor JSON objects do: with "type": "doc". Its second member, content, contains a nested array of all the child blocks — i.e., everything entered in the Block Editor.

Once the JSON object is parsed, your options for rendering are virtually limitless. Grab a Javascript framework of your choice and get creative!

Here's one compact example of rendering blocks using React.

On this page