Was this page helpful?

Rich Text

Rich Text is a field type that enables authors to create rich text content, similar to traditional "What you see is what you get" (wysiwyg) editors. Additionally, it allows entries and assets within your Contentful space to be linked dynamically and embedded within the flow of the text.

The API response of a Rich Text field is in JSON format, without shortcodes or empty <p></p> tags associated with traditional wysiwyg responses.

Rich Text on the Web App

An animated GIF of scrolling through a Rich Text editor field with lots of different types of rich content

The menu bar at the top of the Rich Text editor provides authors with all the usual text formatting capabilities, including creating links to a static URL, and inserting Contentful entries and assets from within your Contentful space.

The Embed Entry button (top right) embeds a Contentful entry as a block or inline element.

Rich Text on the API Response

The Rich Text API response is returned as a JSON array of nodes that follows the format of an abstract syntax tree. The following is an example of an API response which returns a paragraph — "This text is important" — with the word "important" marked as bold:

An image of a JSON response of a Rich Text field, highlighting the node types and mark types, such as bold

Customization

A key aspect of Rich Text is the possibility to customize the field in a way that authors are limited to using specified formatting options.

For example, you can limit the formatting options to only include paragraph tags, or limit the kinds of entries that can be hyperlinked or embedded.

A screenshot of the Rich Text editor, showing the differences in the top toolbar with formatting options adjusted

Customization can be done on the Web App or through the API.

Embedded and Linked Entries

Rich Text allows hyperlinking and embedding entries in the flow of text. If you're working with React, you can pass a React component or plain HTML as a rendered component of this data. This enables you to render your content the way you need to on the front end, such as by adding CSS classes, data attributes and so on.

For example, you might want to:

  • Use custom anchor link wrappers, such as a React Router link or a NextJS Link in your single page application
  • Use the Contentful Images API to resize, crop and manipulate an image
  • Render a widget such as an image gallery, a product description box, a sign up form, an annotation window or anything else!

The following screenshot shows a hyperlinked entry, followed by an embedded entry.

Screenshot of an embedded hyperlink and embedded entry in the Rich Text field editor

This is an example of an API response for a hyperlinked entry:

{
  data: {
    target: {
      sys: {
        id: "7GI6AkMKWIqiiUIuG0uAO",
        type: "Link",
        linkType: "Entry"
      }
    }
  },
  content: [
    {
      marks: [ ],
      value: "the link text",
      nodeType: "text"
    }
  ],
  nodeType: "entry-hyperlink"
}

and this is an example of an API response for an embedded entry:

{
  data: {
    target: {
      sys: {
        id: "3v7XvVk8ZyQww8WsS2ocou",
        type: "Link",
        linkType: "Entry"
      }
    }
  },
  content: [
    {
      marks: [ ],
      value: "",
      nodeType: "text"
    }
  ],
    nodeType: "embedded-entry-inline"
}

In both cases, the response is a Contentful object. If the response gets consumed with the Contenful SDKs, it gets resolved and is inline in the API response.

To sum up:

  • Hyperlinking an entry means to render an anchor link that points towards the URL of a separate entry.
  • Embedding an entry means to render the contents of this linked Entry in the flow of text, whether on an inline or a block level.

Rendering Linked Assets and Entries in the Rich Text Response in React

If you're using React, we recommend using the Contentful Rich Text React Renderer available from NPM.

The Rich Text response from the API returns embedded assets and entries as separate nodes, which are linked to where they appear in the flow of the Rich Text field by their system IDs (sys.id).

To render your linked entries and assets inline with the rest of your Rich Text response (or wherever you'd like), you'll need to parse the linked asset/entry nodes, and find their reference according to their block type when rendering the content.

Code example

The following is an example of how to render an embedded image asset inline with the Rich Text response.

This is an example of a Rich Text API response containing a paragraph and an embedded image asset:


{
  "json": {
    "nodeType": "document",
    "data": {},
    "content": [
      {
        "nodeType": "paragraph",
        "content": [
          {
            "nodeType": "text",
            "value": "This is a paragraph!",
            "marks": [],
            "data": {}
          }
        ],
        "data": {}
      },
      {
        "nodeType": "embedded-asset-block",
        "content": [],
        "data": {
          "target": {
            "sys": {
              "id": "12345", // you'll see this ID referenced in `links.assets.block` array below
              "type": "Link",
              "linkType": "Asset"
            }
          }
        }
      },
    ]
  }
  "links": {
    "assets": {
      "block": [
        {
          "sys": {
            "id": "12345" // this is the ID we saw returned with the `nodeType: "embedded-asset-block"` in the json.content array
          },
          "url": "https://imageurl.png",
          "title": "this-is-an-image",
          "width": 500,
          "height": 500,
          "description": "This is the description"
        },
      ]
    }
  }
}

A common solution to rendering the embedded asset inline with the Rich Text response in JavaScript is to create a map of the assets (id: asset), and find the asset to display in the map when rendering an asset block.

This following code is an example using the rich-text-react-render:

import { documentToReactComponents } from '@contentful/rich-text-react-renderer';

// Create a bespoke getRenderOptions function

function getRenderOptions(links, isBlogPost = false) {

  // create an asset block map

  const assetBlockMap = new Map();

  // loop through the assets and add them to the map

  for (const asset of links.assets.block) {
    assetBlockMap.set(asset.sys.id, asset);
  }

  return {
    renderNode: {

      // ... other options ...

      [BLOCKS.EMBEDDED_ASSET]: (node, next) => {

        // Find your asset in the map

        const asset = assetBlockMap.get(
          node.data.target.sys.id,
        );

        return (

          // Your component/HTML with the data from the asset

        );
      },
    }
  }

// Render your Rich Text content in the DOM

export default function MyComponent({ richTextResponse }) {
  return (
    <>
      {documentToReactComponents(richTextResponse.json, getRenderOptions(richTextResponse.links));}
    </>
  )
}

Rich Text Commands

Rich Text Commands is a power-user feature that increases the efficiency of editors working with structured content in the Rich Text editor. This feature enables the user embed assets and entries using a command panel without leaving the editor context or keyboard. The command panel opens as soon as the user types a slash (/).

Rules of Rich Text

  • The document must have only one root node with nodeType: 'document'.
  • Nested Documents are not allowed.
  • Nodes in the document can be of type Block, Inline or Text, see: type definitions, list of supported blocks, inlines.
  • Document can contain only nodes type of Block as direct children.
  • Blocks can contain nodes of type Block, Inline, or Text.
  • Nested Blocks are whitelisted, see the list of containers.
  • Void nodes are whitelisted, the list of void nodes.
  • Inlines can contain nodes of type Inline or Text.
  • Text can have a list of Marks associated with it, see list of supported marks.
  • Sibling Text nodes with equal marks should be grouped.
  • Custom node types, data properties and marks are not allowed.

Next steps

Not what you’re looking for? Try our FAQ.