Advanced Rich Text Templating

This article explains how to customize the output of Rich Text with the HTML Serializer.


Introduction

The HTML Serializer function changes the HTML output of a Rich Text component. This function takes a Rich text element from Prismic and specifies how that content should be rendered in HTML. For example:

  • Adding a class to all paragraph elements
  • Preventing images from being surrounded by a paragraph element
  • Adding a class to all hyperlink elements
  • Adding <em> tags to italic text
  • And more.

For this HTML Serializer to work, you must ensure that you are using the prismic-reactjs kit. The prismic-reactjs plugin has a built-in serializer that handles text rendered by the <RichText /> component, but you can also define your own HTML Serializer.


HTML Serializer Example

First, create a file called html-serializer.js file somewhere in your project folder, and then when you call this function link to the file path. The HTML Serializer receives the following arguments: type, element, content, children.

type

The type of the element, such as "paragraph" or "list-item"

element

The complete element, represented as an object

content

The string content of the element

children

Any children contained within the element

Here are the following examples of an HTML Serializer:

In the first example, we explain how HTML Serializer prevents images from being surrounded by a paragraph element and adds a custom class to all hyperlink and paragraph elements.

Copy
import React from 'react'
import { Elements } from 'prismic-richtext'
import { linkResolver } from './example_path_to_linkResolver'

// -- Function to add unique key to props
const propsWithUniqueKey = function(props, key) {
  return Object.assign(props || {}, { key })
}

// -- HTML Serializer
// This function will be used to change the way the HTML is loaded
const htmlSerializer = function(type, element, content, children, key) {
  var props = {}

  switch(type) {
    // Add a class to paragraph elements
    case Elements.paragraph:
      props = {className: 'paragraph-class'}
      return React.createElement('p', propsWithUniqueKey(props, key), children)

    // Don't wrap images in a <p> tag
    case Elements.image:
      props = { src: element.url , alt: element.alt || '' }
      return React.createElement('img', propsWithUniqueKey(props, key))

    // Add a class to hyperlinks
    case Elements.hyperlink:
      const targetAttr = element.data.target ? { target: element.data.target } : {}
      const relAttr = element.data.target ? { rel: 'noopener' } : {}
      props = Object.assign({
        className: 'link-class',
        href: element.data.url || linkResolver(element.data)
      }, targetAttr, relAttr)
      return React.createElement('a', propsWithUniqueKey(props, key), children)

    // Return null to stick with the default behavior
    default:
      return null
  }
}

export default htmlSerializer

Make sure to add a default case that returns null. This will leave all the other elements untouched.

Hyperlinks

To modify the output for the hyperlink element, you will need to use a Link Resolver function. Learn more about the Link resolver function here.

Here is another example that shows you how to modify all of the available Rich Text elements.

Copy
import React from 'react';
import { RichText, Elements } from 'prismic-reactjs';

// -- Function to add unique key to props
const propsWithUniqueKey = function(props, key) {
  return Object.assign(props || {}, { key });
};

// -- HTML Serializer
const htmlSerializer = function(type, element, content, children, key) {

  var props = {};

  switch(type) {
      
    case Elements.heading1: // Heading 1
      return React.createElement('h1', propsWithUniqueKey(props, key), children);
      
    case Elements.heading2: // Heading 2
      return React.createElement('h2', propsWithUniqueKey(props, key), children);
      
    case Elements.heading3: // Heading 3
      return React.createElement('h3', propsWithUniqueKey(props, key), children);
      
    case Elements.heading4: // Heading 4
      return React.createElement('h4', propsWithUniqueKey(props, key), children);
      
    case Elements.heading5: // Heading 5
      return React.createElement('h5', propsWithUniqueKey(props, key), children);
      
    case Elements.heading6: // Heading 6
      return React.createElement('h6', propsWithUniqueKey(props, key), children);
      
    case Elements.paragraph: // Paragraph
      return React.createElement('p', propsWithUniqueKey(props, key), children);
      
    case Elements.preformatted: // Preformatted
      return React.createElement('pre', propsWithUniqueKey(props, key), children);
      
    case Elements.strong: // Strong
      return React.createElement('strong', propsWithUniqueKey(props, key), children);
      
    case Elements.em: // Emphasis
      return React.createElement('em', propsWithUniqueKey(props, key), children);
      
    case Elements.listItem: // Unordered List Item
      return React.createElement('li', propsWithUniqueKey(props, key), children);
      
    case Elements.oListItem: // Ordered List Item
      return React.createElement('li', propsWithUniqueKey(props, key), children);
      
    case Elements.list: // Unordered List
      return React.createElement('ul', propsWithUniqueKey(props, key), children);
      
    case Elements.oList: // Ordered List
      return React.createElement('ol', propsWithUniqueKey(props, key), children);
      
    case Elements.image: // Image
      const linkUrl = element.linkTo ? element.linkTo.url || linkResolver(element.linkTo) : null;
      const linkTarget = (element.linkTo && element.linkTo.target) ? { target: element.linkTo.target } : {};
      const linkRel = linkTarget.target ? { rel: 'noopener' } : {};
      const img = React.createElement('img', { src: element.url , alt: element.alt || '' });
      return React.createElement(
        'p',
        propsWithUniqueKey({ className: [element.label || '', 'block-img'].join(' ') }, key),
        linkUrl ? React.createElement('a', Object.assign({ href: linkUrl }, linkTarget, linkRel), img) : img
      );
      
    case Elements.embed: // Embed
      props = Object.assign({
        "data-oembed": element.oembed.embed_url,
        "data-oembed-type": element.oembed.type,
        "data-oembed-provider": element.oembed.provider_name,
      }, element.label ? {className: element.label} : {});
      const embedHtml = React.createElement('div', {dangerouslySetInnerHTML: {__html: element.oembed.html}});
      return React.createElement('div', propsWithUniqueKey(props, key), embedHtml);
      
    case Elements.hyperlink: // Image
      const targetAttr = element.data.target ? { target: element.data.target } : {};
      const relAttr = element.data.target ? { rel: 'noopener' } : {};
      props = Object.assign({ 
        href: element.data.url || linkResolver(element.data)
      }, targetAttr, relAttr);
      return React.createElement('a', propsWithUniqueKey(props, key), children);
      
    case Elements.label: // Label
      props = element.data ? Object.assign({}, { className: element.data.label }) : {};
      return React.createElement('span', propsWithUniqueKey(props, key), children);
      
    case Elements.span: // Span
      if (content) {
        return content.split("\n").reduce((acc, p) => {
          if (acc.length === 0) {
            return [p];
          } else {
            const brIndex = (acc.length + 1)/2 - 1;
            const br = React.createElement('br', propsWithUniqueKey({}, brIndex));
            return acc.concat([br, p]);
          }
        }, []);
      } else {
        return null;
      }

    default: // Always include a default that returns null
      return null;
  }
};

Use the HTML serializer Function

To use the HTML serializer function, you need to do two things:

  • First, import the HTML serializer function in the rich text component that is rendering a rich text field.
  • Second, pass the Serializer function into the <RichText htmlSerializer={} /> property of a RichText component.
Copy
import {htmlSerializer} from './example_path_to_htmlSerializer.js_file'

<RichText 
  render={document.data.rich_text} 
  htmlSerializer={htmlSerializer}
/>

Related Articles


Was this article helpful?
Not really
Yes, Thanks

Can't find what you're looking for? Get in touch with us on our Community Forum.