Template Rich Text and Titles

Learn how to customize and template a Rich Text or Title field output in your Gatsby project.


🕙 Before reading

This page assumes that you have saved the response of your queries in a variable named document and that you've already installed the prismic-reactjs library. You'll use this library to import helper components into your templates, as shown below:

import { Link, RichText } from 'prismic-reactjs'

Rich Text and Title fields

Rich Text and Title fields are delivered in an array that contains information about the text structure. Here's an example of a Rich Text field (Title fields follow the same format):

Copy
"example_rich_text": {
  "html": "<p>The future is here.</p>",
  "raw": [
    {
      "type": "paragraph",
      "text": "The future is here.",
      "spans": []
    }
  ],
  "text": "The future is here."
}

Render as HTML

The basic usage of the Rich Text or Title field is to use the <RichText /> component from prismic-reactjs to transform the Rich Text content into HTML using the raw option of the field:

Copy
<RichText render={document.data.example_rich_text.raw} />

Render as plain text

Occasionally, you may require to render not a component but a plain string. To do so, render the text option of the field:

Copy
<h1>{document.data.example_rich_text.text}</h1>

Links in Rich Text fields

If your Rich Text field has links, you'll want to render them appropriately with Gatsby Link to handle links to internal documents internal links, and custom <a> tags for external URLs. For that, create a custom serializeHyperlink.

In this example, we provide you with a full component that will render the appropriate custom link depending on the type of the link_type that is being passed to the Rich Text field and we show you an example of how to pass the customLink to the serializeHyperlink option:

  • CustomLink.js
  • Example usage
Copy
import React from 'react'
import { Link } from 'gatsby'
import { linkResolver } from './path-to-LinkResolver'

export const CustomLink = (type, element, content, children, index) => {
  if (element.data.link_type === 'Document') {
    <Link to={linkResolver(element.data)} key={element.data.id}>
      {content}
    </Link>
  }

  if (element.data.link_type === 'Web') {
    <a id={element.data.id} href={element.data.url}>
      {content}
    </a>
  }
  return null
}
Copy
import * as React from 'react'
import { RichText } from 'prismic-reactjs'
import CustomLink from '../example_path_to_CustomLink'

export const MyComponent = (document) => (
  <div>
    <RichText
      render={document.data.example_text_with_links}
      serializeHyperlink={CustomLink}
    />
  </div>
)

ℹ️ Link Resolver

The RichText component has a linkResolver property where you can pass in a Link Resolver function in the previous example. This is necessary to provide the correct URL for any Link to a Document in your Rich Text content.

To learn more about how to set up a Link Resolver, check out our Link Resolving page.


The HTML Serializer

The HTML Serializer defines a customized output of your Rich Text fields. (For example, text with the codespan should be wrapped in <code> tags.) prismic-reactjs contains a default HTML Serializer for standard markup, but you can create your own HTML Serializer and then pass it to a RichText component. See how we do this in the following example:

Copy
<RichText render={document.data.example_rich_text.raw} htmlSerializer={htmlSerializer} />

Here are two examples of an HTML Serializer.

1. First example: This HTML Serializer will prevent image elements from being wrapped in paragraph tags and add a custom class to all hyperlink and paragraph elements.

2. Second example: This HTML Serializer shows you how to change all of the available Rich Text elements. The examples render the normal output of each field, so you can modify any of these to get your desired results.

  • 1st example
  • 2nd example
Copy
import * as React from 'react'
import { Elements } from 'prismic-richtext'

import { linkResolver } from './example_path_to_linkResolver'

// -- HTML Serializer
// This function will be used to change the way the HTML is loaded
const htmlSerializer = function (type, element, content, children, key) {
  switch (type) {
    // Add a class to paragraph elements
    case Elements.paragraph:
      return (
        <p key={key} className="paragraph-class">
          {children}
        </p>
      )

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

    // Add a class to hyperlinks
    case Elements.hyperlink:
      return (
        <a
          key={key}
          href={element.data.url || linkResolver(element.data)}
          target={element.data.target}
          rel={element.data.target ? 'noopener' : undefined}
          className="link-class"
        >
          {children}
        </a>
      )

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

export default htmlSerializer
Copy
import * as React from 'react'
import { Link } from 'gatsby'
import { Elements } from 'prismic-richtext'
import { Link as PrismicLink } from 'prismic-reactjs'

import { linkResolver } from './example_path_to_linkResolver'

// -- HTML Serializer
const htmlSerializer = function (type, element, content, children, key) {
  switch (type) {
    case Elements.heading1: // Heading 1
      return <h1 key={key}>{children}</h1>

    case Elements.heading2: // Heading 2
      return <h2 key={key}>{children}</h2>

    case Elements.heading3: // Heading 3
      return <h3 key={key}>{children}</h3>

    case Elements.heading4: // Heading 4
      return <h4 key={key}>{children}</h4>

    case Elements.heading5: // Heading 5
      return <h5 key={key}>{children}</h5>

    case Elements.heading6: // Heading 6
      return <h6 key={key}>{children}</h6>

    case Elements.paragraph: // Paragraph
      return <p key={key}>{children}</p>

    case Elements.preformatted: // Preformatted
      return <pre key={key}>{children}</pre>

    case Elements.strong: // Strong
      return <strong key={key}>{children}</strong>

    case Elements.em: // Emphasis
      return <em key={key}>{children}</em>

    case Elements.listItem: // Unordered List Item
    case Elements.oListItem: // Ordered List Item
      return <li key={key}>{children}</li>

    case Elements.list: // Unordered List
      return <ul key={key}>{children}</ul>

    case Elements.oList: // Ordered List
      return <ol key={key}>{children}</ol>

    case Elements.image:
      const linkUrl = element.linkTo
        ? element.linkTo.url || linkResolver(element.linkTo)
        : null

      return (
        <p
          key={key}
          className={[element.label, 'block-img'].filter(Boolean).join(' ')}
        >
          {linkUrl ? (
            <a
              href={linkUrl}
              target={element.linkTo?.target}
              rel={element.linkTo?.target ? 'noopener' : undefined}
            >
              <img src={element.url} alt={element.alt || ''} />
            </a>
          ) : (
            <img src={element.url} alt={element.alt || ''} />
          )}
        </p>
      )

    case Elements.embed: // Embed
      return (
        <div
          key={key}
          data-oembed={element.oembed.embed_url}
          data-oembed-type={element.oembed.type}
          data-oembed-provider={element.oembed.provider_name}
          className={element.label}
          __dangerouslySetInnerHTML={{ __html: element.oembed.html }}
        />
      )

    case Elements.hyperlink: // Hyperlinks
      const url = PrismicLink.url(element.data, linkResolver)

      if (element.data.link_type === 'Document') {
        return (
          <Link key={key} to={url}>
            {content}
          </Link>
        )
      }

      return (
        <a
          key={key}
          href={url}
          target={element.data.target}
          rel={element.data.target ? 'noopener' : undefined}
          className="link-class"
        >
          {children}
        </a>
      )

    case Elements.label: // Label
      return (
        <label key={key} className={element.data.label}>
          {children}
        </label>
      )

    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
            return acc.concat([<br key={brIndex} />, p])
          }
        }, [])
      } else {
        return null
      }

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

export default htmlSerializer

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.