Rich Text
On this page, you’ll learn how to work with rich text from Prismic.
Prismic provides the tools to write, save, query, and render rich text content.
Rich text format
Rich text is text that can be formatted in a user interface. Prismic provides a rich text editor that saves the content in a simple data structure designed for web publishing.
Most people are comfortable creating content in a rich text editor. But rich text from an application like Microsoft Word or Google Docs has very complicated encoding that can be difficult to work with.
Prismic stores text in a particular JSON format that we call “structured text,” which is portable and adaptable. Other content management systems often store text content as HTML or Markdown, like this:
{
"blog_post_content": "<div>I started reading <em>Great Expectations</em>!</div>"
}
HTML or Markdown can be convenient at first, but they will become restrictive over time. To customize the markup or the content, you need to add complicated logic. Prismic’s rich text format is designed to allow convenient customizations.
Here is what rich text looks like on the Prismic API:
{
"blog_post_content": [
{
"type": "paragraph",
"text": "I started reading Great Expectations!",
"spans": [
{
"start": 18,
"end": 36,
"type": "em"
}
]
}
]
}
Rich text is presented as an array. Each item in the array is a block of text (a block-level element like a heading, paragraph, or preformatted). Each item contains the raw text string, a block type, and some meta information that describes the text. The meta-information will describe the inline elements, like emphasis, strong, and links.
Here are all the properties of rich text:
type string | The type of block-level formatting. Values:
|
text string | The text content of the element. Example: |
direction string | A string that specifies the direction of text only
if right-to-left formatting is applied. Value:
|
spans array | An array that describes inline formatting. |
spans[index] object | A single span of inline formatting. |
spans[index].start number | The zero-indexed position of the start of a span
(inclusive). Example: |
spans[index].end number | The position of the final character at the end of a
span. Example: |
spans[index].type string | The type of inline formatting. Values: |
spans[index].url string | The URL of a media item if the element is an image. |
spans[index].alt string | The alt text of an image if the element is an image. |
spans[index].copyright string | The copyright of an image if the element is an image. |
| An object that contains the dimensions of an image if the element is an image. |
| The width of an image if the element is an image. |
| The height of an image if the element is an image. |
spans[index].data object | An object that contains additional data if the element is a label or hyperlink. See the rich text labels section and fields article for more information. |
spans[index].oembed object | An object that contains additional data if the element is an embed. See the fields article for more information. |
It is still possible to edit and publish HTML and Markdown with Prismic. To do so, configure a rich text field with only the pre
element enabled. Your content editors will see a monospace editor. Use the helper methods from Prismic’s open-source packages to convert the field to plain text in your app. Then, you’ll have basic HTML or Markdown, which you can use as needed in your website.
Rich text fields
There are three text fields available for the Prismic editor:
- Key text
- Titles
- Rich text
Key text is the only field that does not use structured text. It is for short, unformatted text. In the JSON API response, key text is delivered as a simple primitive string:
{
"example_key_text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
}
The rich text and title fields are both structured text. The title field has two unique restrictions:
- The element must be a heading
- It only allows one block of text
The rich text field has no restrictions. You can customize the rich text field that appears in the Prismic Editor with the following element types:
- Heading elements (h1, h2, h3, h4, h5, h6)
- Normal text paragraph
- Strong or bold text
- Emphasized or italic text
- Preformatted text
- Inline hyperlink to the web, to a document, or a media item
- Image
- Embed to a service URL supporting oEmbed
- Unordered list
- Ordered list
- Right-to-left text
- Custom labels
To learn more about how to write rich text, read Edit Rich Text.
Use key text for a simple piece of metadata, such as key terms. Use the title field for titles and headings and the rich text for blocks of text.
Query rich text
To access the content from a rich text field in a document, fetch the document from the API, like in the following example:
const doc = await client.getByUID("post", "my-first-post");
This line fetches a document based on its unique identifier — or uid.
You can filter API results by rich text using three filters:
fulltext
to search for documents that contain a given stringhas
to search for documents where a rich text field is populated with contentmissing
to search for documents where a rich text field is not populated with content
Note: has
and missing
don’t work with fields in slices or groups.
Here’s a fulltext
query:
import { filter } from "@prismicio/client";
const doc = await client.getByUID("page", uid, {
filters: [filter.fulltext("document", "Hello")],
});
Render rich text
Here’s what rich text from the Prismic API looks like:
// API response example of a rich text field
{
//...
"example_rich_text": {
"type": "StructuredText",
"config": {
"single": "paragraph",
"label": "Rich Content",
"placeholder": "Rich Content",
"labels": ["right-align", "center-align"]
}
}
}
When you fetch content from the Prismic API, you cannot immediately inject it into your web app. First, you must process it with one of Prismic’s open-source packages. Our packages include functions and components to turn rich text JSON into HTML.
import { PrismicRichText } from "@prismicio/react";
<PrismicRichText field={document.data.myText} />;
Customize rich text
Prismic offers two features for advanced rich text customization: custom labels and the rich text serializer.
Rich text labels
For special formatting in your rich text or title fields, you can add custom formatting by using labels. For example, by default, the Prismic kits will render a custom label as a <span>
with a class of the label’s name. (This is an advanced configuration that can only be set up in the JSON editor.) Here is an example of a rich text field with the label options "right-align"
and "center-align"
:
{
"example_rich_text": {
"type": "StructuredText",
"config": {
"single": "paragraph",
"label": "Rich Content",
"placeholder": "Rich Content",
"labels": ["right-align", "center-align"]
}
}
}
Rich text serializer
A rich text serializer determines how each element in a rich text field should be rendered. For example, if you’re rendering HTML, you might want a heading1 element to be wrapped in <h1>
tags.
Prismic’s development package, @prismicio/client
, converts rich text content into HTML by default, so it’s not necessary to provide your own rich text serializer. However, you might want to change how rich text is serialized. Maybe you want to add a very precise set of class names to certain elements or to add a unique HTML tag based on the label. In that case, you can provide your own rich text serializer to alter the serialization selectively.
Each key on the rich text serializer object is the name of a rich text element (such as paragraph
, label
, or heading1
) and the value should be a function that returns a converted value.
Here’s a brief example. This code says, “if the type of the element is ‘label,’ return the text inside strong
tags with a class of the label.”
import * as prismic from "@prismicio/client";
import { PrismicRichText } from "@prismicio/react";
/**
* In the PrismicRichText component from @prismicio/react,
* the rich text serializer is handled by the `components`
* prop.
*/
const components = {
label: ({ node, children }) => (
<strong className={node.data.label}>{children}</strong>
),
};
export default function Text({ slice }) {
return (
<section>
<PrismicRichText
field={slice.primary.text}
components={components}
/>
</section>
);
}
The methods on the components object receive an params object with four parameters: children
, key
, type
, node
, text
.
| An array of all child elements, which have already been serialized. Example:
|
| A unique key for React’s key prop. |
| A description of the entire element. For inline elements, this includes the start index, end index, type, and — if the element is a custom label — the name of the label. Example:
For block-level elements (eg: paragraph, headings, pre), this includes the type, the **text **content, and an array containing all of the inline elements. Example:
|
| The content of the element. Example: |
| The type of the element.Example: |
To see how @prismicio/client
can serialize every available element, view the example in the @prismicio/richtext Technical Reference or this simplified version of a rich text serializer handling all cases:
const linkResolver = (doc) => "/" + doc.uid;
const serializer = {
heading1: ({ children }) => `<h1>${children}</h1>`,
heading2: ({ children }) => `<h2>${children}</h2>`,
heading3: ({ children }) => `<h3>${children}</h3>`,
heading4: ({ children }) => `<h4>${children}</h4>`,
heading5: ({ children }) => `<h5>${children}</h5>`,
heading6: ({ children }) => `<h6>${children}</h6>`,
paragraph: ({ children }) => `<p>${children}</p>`,
preformatted: ({ node }) =>
`<pre>${JSON.stringify(node.text)}</pre>`,
strong: ({ children }) => `<strong>${children}</strong>`,
em: ({ children }) => `<em>${children}</em>`,
listItem: ({ children }) => `<li>${children}</li>`,
oListItem: ({ children }) => `<li>${children}</li>`,
list: ({ children }) => `<ul>${children}</ul>`,
oList: ({ children }) => `<ol>${children}</ol>`,
image: ({ node }) => {
const linkUrl = node.linkTo
? linkResolver(node.linkTo)
: null;
const linkTarget =
node.linkTo && node.linkTo.target
? `target="${node.linkTo.target}" rel="noopener"`
: "";
const wrapperClassList = [
node.label || "",
"block-img",
];
const img = `<img src="${node.url}" alt="${
node.alt ? node.alt : ""
}" copyright="${node.copyright ? node.copyright : ""}" />`;
return `
<p class="${wrapperClassList.join(" ")}">
${linkUrl ? `<a ${linkTarget} href="${linkUrl}">${img}</a>` : img}
</p>
`;
},
embed: ({ node }) => `
<div data-oembed="${node.oembed.embed_url}"
data-oembed-type="${node.oembed.type}"
data-oembed-provider="${node.oembed.provider_name}"
${label(node)}>
${node.oembed.html}
</div>
`,
hyperlink: ({ node, children }) => {
const target = node.data.target
? `target="${node.data.target}" rel="noopener"`
: "";
const url = linkResolver(node.data);
return `<a ${target} href="${url}">${children}</a>`;
},
label: ({ node, children }) => {
return `<span class="${node.data.label}">${children}</span>`;
},
span: ({ text }) => (text ? text : ""),
};