@ignw/rich-text-react-renderer
v14.1.3
Published
React renderer for the Contentful rich text field type.
Downloads
2
Readme
rich-text-react-renderer
React renderer for the Contentful rich text field type.
Installation
Using npm:
npm install @contentful/rich-text-react-renderer
Using yarn:
yarn add @contentful/rich-text-react-renderer
Usage
import { documentToReactComponents } from '@contentful/rich-text-react-renderer';
const document = {
nodeType: 'document',
data: {},
content: [
{
nodeType: 'paragraph',
data: {},
content: [
{
nodeType: 'text',
value: 'Hello world!',
marks: [],
data: {}
},
],
},
],
};
documentToReactComponents(document); // -> <p>Hello world!</p>
import { documentToReactComponents } from '@contentful/rich-text-react-renderer';
const document = {
nodeType: 'document',
content: [
{
nodeType: 'paragraph',
content: [
{
nodeType: 'text',
value: 'Hello',
marks: [{ type: 'bold' }],
},
{
nodeType: 'text',
value: ' world!',
marks: [{ type: 'italic' }],
},
],
},
],
};
documentToReactComponents(document);
// -> <p><b>Hello</b><u> world!</u></p>
You can also pass custom renderers for both marks and nodes as an optional parameter like so:
import { BLOCKS, MARKS } from '@contentful/rich-text-types';
import { documentToReactComponents } from '@contentful/rich-text-react-renderer';
const document = {
nodeType: 'document',
content: [
{
nodeType: 'paragraph',
content: [
{
nodeType: 'text',
value: 'Hello',
marks: [{ type: 'bold' }],
},
{
nodeType: 'text',
value: ' world!',
marks: [{ type: 'italic' }],
},
],
},
],
};
const Bold = ({ children }) => <p className="bold">{children}</p>;
const Text = ({ children }) => <p className="align-center">{children}</p>;
const options = {
renderMark: {
[MARKS.BOLD]: text => <Bold>{text}</Bold>,
},
renderNode: {
[BLOCKS.PARAGRAPH]: (node, children) => <Text>{children}</Text>,
},
renderText: text => text.replace('!', '?'),
};
documentToReactComponents(document, options);
// -> <p class="align-center"><p class="bold">Hello</p><u> world?</u></p>
Last, but not least, you can pass a custom rendering component for an embedded entry:
import { BLOCKS } from '@contentful/rich-text-types';
import { documentToReactComponents } from '@contentful/rich-text-react-renderer';
const document = {
nodeType: 'document',
content: [
{
nodeType: 'embedded-entry-block',
data: {
target: (...)Link<'Entry'>(...);
},
},
]
};
const CustomComponent = ({ title, description }) => (
<div>
<h2>{title}</h2>
<p>{description}</p>
</div>
);
const options = {
renderNode: {
[BLOCKS.EMBEDDED_ENTRY]: (node) => {
const { title, description } = node.data.target.fields;
return <CustomComponent title={title} description={description} />
}
}
};
documentToReactComponents(document, options);
// -> <div><h2>[title]</h2><p>[description]</p></div>
The renderNode
keys should be one of the following BLOCKS
and INLINES
properties as defined in @contentful/rich-text-types
:
BLOCKS
DOCUMENT
PARAGRAPH
HEADING_1
HEADING_2
HEADING_3
HEADING_4
HEADING_5
HEADING_6
UL_LIST
OL_LIST
LIST_ITEM
QUOTE
HR
EMBEDDED_ENTRY
EMBEDDED_ASSET
INLINES
EMBEDDED_ENTRY
(this is different from theBLOCKS.EMBEDDED_ENTRY
)HYPERLINK
ENTRY_HYPERLINK
ASSET_HYPERLINK
The renderMark
keys should be one of the following MARKS
properties as defined in @contentful/rich-text-types
:
BOLD
ITALIC
UNDERLINE
CODE
The renderText
callback is a function that has a single string argument and returns a React node. Each text node is evaluated individually by this callback. A possible use case for this is to replace instances of \n
produced by Shift + Enter
with <br/>
React elements. This could be accomplished in the following way:
const options = {
renderText: text => {
return text.split('\n').reduce((children, textSegment, index) => {
return [...children, index > 0 && <br key={index} />, textSegment];
}, []);
},
};
Note on adding a key
prop in custom renderers:
It is possible to pass a key
prop in the components returned by custom renderers. A good use case for this is in embeded entries using the node's target.sys.id
. It is important not to pass anything that is index-like (e.g. 1 or "1") as it may clash with the default renderers which automatically inject a key
prop using their index in the Contentful rich text AST.
To work around this limitation, just append any non-numeric character to your custom key.
const options = {
renderMark: {
[MARKS.BOLD]: text => {
return <b key={`${text}-key`}>{text}</b>;
},
},
};
Fix render bug with text node
Bug: Contentful returns node with no marks on hyperlink. This breaks the render component.
{
"value": null,
"nodeType": "hyperlink",
"marks": null,
"data": {
"uri": "https:somewhere.com/"
},
"content": [
{
"nodeType": "text",
"value": "the link text",
"content": null
}
]
},
see above for example JSON