GraphCMS boasts an impressive collection of Field Types that you can use when content modelling. These field types range from the core GraphQL scalar types, to custom Asset, Location, JSON, and, RichText scalars.
In this post we'll look at the Rich Text field. We'll take a peak at how you can query, and mutate Rich Text using the Content API.
When editing content, you'll be presented with a text editor that gives you the ability to format paragraphs, headings, lists, and embed iframes, tables, and assets.
When you save content, it is saved as an abstract syntax tree (AST), and can be queried in the format of HTML, Markdown, Text, and the "raw" AST itself (JSON). The AST is based on Slate.
If you open the API Playground documentation, you'll be able to search for the RichText
type.
You'll see it returns its own GraphQL type:
type RichText {raw: RichTextAST!html: String!markdown String!text: String!}
How you use the fields for RichText
will depend on your application. Let's take a look at the different methods of fetching, displaying, and mutating rich text below.
Querying Rich TextAnchor
Just like any other field in your content model, you can fetch your rich text content, but in any (or all) of the formats typed above.
For example, let's fetch the raw
, html
, markdown
, and text
values for the custom field content
which is of type RichText
:
{articles {content {rawhtmlmarkdowntext}}}
This query will return the following:
{"data": {"articles": [{"content": {"raw": {"children": [{"type": "paragraph","children": [{"text": "GraphQL CMS"}]}]},"html": "<p>GraphQL CMS</p>","markdown": "GraphQL CMS\n","text": "GraphQL CMS"}}]}}
For the purposes of this article, I'm just returning a single paragraph, but for each of the different nodes you add to the rich text editor, it will return a "node" with type
, and the children
.
Slate has different node types, they are:
- A root-level
Editor
node that contains the entire document's content - Container
Element
nodes which have semantic meaning in your domain. - And leaf-level
Text
nodes which contain the document's text.
These combined are shown above in the query response. Learn more about Slate nodes.
Rendering Rich TextAnchor
Depending on which of the RichText types you are querying, your presentation implementation will vary.
raw
Anchor
When using the raw
AST (Slate nodes) you will have ultimate control over how these nodes are presented to the user.
Let's have a look at a more complex AST response for the first two paragraphs of this article:
{"data": {"articles": [{"content": {"raw": {"children": [{"type": "paragraph","children": [{"text": "GraphCMS boasts an impressive collection of "},{"href": "https://graphcms.com/docs/api-reference/schema/field-types","type": "link","children": [{"text": "Field Types"}]},{"text": " that you can use when content modelling. These field types range from the core GraphQL scalar types, to custom "},{"href": "https://graphcms.com/docs/api-reference/schema/field-types#asset","type": "link","children": [{"text": "Asset"}]},{"text": ", "},{"href": "https://graphcms.com/docs/api-reference/schema/field-types#location","type": "link","children": [{"text": "Location"}]},{"text": ", "},{"href": "https://graphcms.com/docs/api-reference/schema/field-types#json","type": "link","children": [{"text": "JSON"}]},{"text": ", and, "},{"href": "https://graphcms.com/docs/api-reference/schema/field-types#rich-text","type": "link","children": [{"text": "RichText"}]},{"text": " scalars."}]},{"type": "paragraph","children": [{"text": ""}]},{"type": "paragraph","children": [{"text": "In this post we'll look at the Rich Text field. We'll take a peak at how you can query, and mutate Rich Text using the Content API."}]},{"type": "paragraph","children": [{"text": ""}]},{"src": "https://media.graphcms.com/N3JOKsXrT9ezCU4Ba6LI","type": "image","title": "Screenshot 2021-03-24 at 13.00.14.png","width": 2408,"handle": "N3JOKsXrT9ezCU4Ba6LI","height": 1684,"children": [{"text": ""}],"mimeType": "image/png"},{"type": "paragraph","children": [{"text": ""}]}]}}}]}}
As you can see, we have an array of different node types. It's up to you to display this in your application.
You may begin by having a dictionary (or Map) of your node type renderers as key/value pairs. Slate have an example of how you can use a switch
statement in JavaScript to return different tags based on the type
.
const renderElement = useCallback(({ attributes, children, element }) => {switch (element.type) {case 'quote':return <blockquote {...attributes}>{children}</blockquote>case 'link':return (<a {...attributes} href={element.url}>{children}</a>)default:return <p {...attributes}>{children}</p>}}, [])
html
Anchor
Rendering the HTML of your rich text is quite simple, but comes without much customization. GraphCMS will automatically parse the Slate raw
output into HTML elements you can pass straight to the DOM.
Using the query above to fetch articles, let's now fetch just the html
.
{"data": {"articles": [{"content": {"html": "<p>GraphCMS boasts an impressive collection of <a title=\"https://graphcms.com/docs/api-reference/schema/field-types\" href=\"https://graphcms.com/docs/api-reference/schema/field-types\">Field Types</a> that you can use when content modelling. These field types range from the core GraphQL scalar types, to custom <a title=\"https://graphcms.com/docs/api-reference/schema/field-types#asset\" href=\"https://graphcms.com/docs/api-reference/schema/field-types#asset\">Asset</a>, <a title=\"https://graphcms.com/docs/api-reference/schema/field-types#location\" href=\"https://graphcms.com/docs/api-reference/schema/field-types#location\">Location</a>, <a title=\"https://graphcms.com/docs/api-reference/schema/field-types#json\" href=\"https://graphcms.com/docs/api-reference/schema/field-types#json\">JSON</a>, and, <a title=\"https://graphcms.com/docs/api-reference/schema/field-types#rich-text\" href=\"https://graphcms.com/docs/api-reference/schema/field-types#rich-text\">RichText</a> scalars.</p><p></p><p>In this post we'll look at the Rich Text field. We'll take a peak at how you can query, and mutate Rich Text using the Content API.</p><p></p><img src=\"https://media.graphcms.com/N3JOKsXrT9ezCU4Ba6LI\" alt=\"Screenshot 2021-03-24 at 13.00.14.png\" title=\"Screenshot 2021-03-24 at 13.00.14.png\" width=\"2408\" height=\"1684\" /><p></p>"}}]}}
You can then just output this HTML directly to the page.
If you are using React, it's a little different. However, you can safely (because you know the source of truth) use dangerouslySetInnerHTML
for setting HTML.
For example:
const article = {"content": {"html": "<p>GraphCMS boasts an impressive collection of <a title=\"https://graphcms.com/docs/api-reference/schema/field-types\" href=\"https://graphcms.com/docs/api-reference/schema/field-types\">Field Types</a> that you can use when content modelling. These field types range from the core GraphQL scalar types, to custom <a title=\"https://graphcms.com/docs/api-reference/schema/field-types#asset\" href=\"https://graphcms.com/docs/api-reference/schema/field-types#asset\">Asset</a>, <a title=\"https://graphcms.com/docs/api-reference/schema/field-types#location\" href=\"https://graphcms.com/docs/api-reference/schema/field-types#location\">Location</a>, <a title=\"https://graphcms.com/docs/api-reference/schema/field-types#json\" href=\"https://graphcms.com/docs/api-reference/schema/field-types#json\">JSON</a>, and, <a title=\"https://graphcms.com/docs/api-reference/schema/field-types#rich-text\" href=\"https://graphcms.com/docs/api-reference/schema/field-types#rich-text\">RichText</a> scalars.</p><p></p><p>In this post we'll look at the Rich Text field. We'll take a peak at how you can query, and mutate Rich Text using the Content API.</p><p></p><img src=\"https://media.graphcms.com/N3JOKsXrT9ezCU4Ba6LI\" alt=\"Screenshot 2021-03-24 at 13.00.14.png\" title=\"Screenshot 2021-03-24 at 13.00.14.png\" width=\"2408\" height=\"1684\" /><p></p>"}}function MyComponent() {return <div dangerouslySetInnerHTML={article.content.html} />;}
markdown
Anchor
To present markdown on a page, you'll need a markdown parser that will convert markdown to HTML. Here are a few that come to mind;
Depending on your frontend stack, there will most likely be a markdown renderer for you.
It's important to remember that some renderers will handle the parse and transformation client side, so depending on the length of content, this could increase affect your performance metrics.
If you can, compute the HTML ahead of time, and render only HTML. You might find using the html
output more performant instead.
If you opt to use MDX, you can have even more customisability than you can the raw
AST. You can even inject dynamic React components based on your Markdown node types.
text
Anchor
There aren't many use cases for rendering just the text
other than using it for a "excerpt". This is because any links, or images will be stripped out, and you'll need to sanitize any new lines and breaks yourself before rendering into a DOM element.
For the same Rich Text we created earlier (the first two paragraphs of this article) you'll be presented with the following from the GraphQL query:
GraphCMS boasts an impressive collection of \\nField Types\\n that you can use when content modelling. These field types range from the core GraphQL scalar types, to custom \\nAsset\\n, \\nLocation\\n, \\nJSON\\n, and, \\nRichText\\n scalars.\\n\\nIn this post we'll look at the Rich Text field. We'll take a peak at how you can query, and mutate Rich Text using the Content API.\\n\\n\\n
Mutating Rich TextAnchor
Like every other content model, and field type inside GraphCMS, you can also mutate data using the Mutations API.
You'll typically mutate rich text using the Mutations API if you are accepting rich text submitted by a user in your own application, or if you have built your own content editor on top of GraphCMS.
However you're planning to mutate rich text, you will need to pass it to GraphCMS in the format of the Slate AST nodes we described above.
Here's an example of a Mutation:
mutation createArticle($title:String, $content:RichTextAST) {createArticle(data: {title: $title,content: $content}) {titlecontent {raw}}}
... and the variables:
{"title":"Working with the GraphCMS Rich Text field","content":{"children":[{"type":"paragraph","children":[{"text":"GraphCMS boasts an impressive collection of "},{"href":"https://graphcms.com/docs/api-reference/schema/field-types","type":"link","children":[{"text":"Field Types"}]},{"text":" that you can use when content modelling. These field types range from the core GraphQL scalar types, to custom "},{"href":"https://graphcms.com/docs/api-reference/schema/field-types#asset","type":"link","children":[{"text":"Asset"}]},{"text":", "},{"href":"https://graphcms.com/docs/api-reference/schema/field-types#location","type":"link","children":[{"text":"Location"}]},{"text":", "},{"href":"https://graphcms.com/docs/api-reference/schema/field-types#json","type":"link","children":[{"text":"JSON"}]},{"text":", and, "},{"href":"https://graphcms.com/docs/api-reference/schema/field-types#rich-text","type":"link","children":[{"text":"RichText"}]},{"text":" scalars."}]},{"type":"paragraph","children":[{"text":""}]},{"type":"paragraph","children":[{"text":"In this post we'll look at the Rich Text field. We'll take a peak at how you can query, and mutate Rich Text using the Content API."}]},{"type":"paragraph","children":[{"text":""}]},{"src":"https://media.graphcms.com/N3JOKsXrT9ezCU4Ba6LI","type":"image","title":"Screenshot 2021-03-24 at 13.00.14.png","width":2408,"handle":"N3JOKsXrT9ezCU4Ba6LI","height":1684,"children":[{"text":""}],"mimeType":"image/png"},{"type":"paragraph","children":[{"text":""}]}]}}
Slate provides a nice editor out of the box for React you can use, slate-react
. See "Installing Slate" for more on this.