@ignw/rich-text-react-renderer
TypeScript icon, indicating that this package has built-in type declarations

14.1.3 • Public • Published

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 the BLOCKS.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

Readme

Keywords

none

Package Sidebar

Install

npm i @ignw/rich-text-react-renderer

Weekly Downloads

0

Version

14.1.3

License

MIT

Unpacked Size

176 kB

Total Files

68

Last publish

Collaborators

  • anatidae
  • phil.a.taylor
  • tmartinignw