gatsby-transformer-contentful-richtext should provide a documentToJSX method
See original GitHub issuegatsby-transformer-contentful-richtext being React based should support converting the document output to JSX(very common with Gatsby afaik?).
@sarahbethfederman has been so kind as to write up a version here.
If done, and since this should involve updating the Gatsby plugin docs, it’d be good to show an example of a custom renderNode option that also has inner content like a link, and a common question that’ll probably be sought after, how to use the Gatsby <Link />
element for internal links.:
(Note this is pseudo-code, I don’t think the node side tends to like js files with import statements instead of require statements?)
// `./components/link.js`
import React from 'react'
import {INLINES, BLOCKS, MARKS} from '@contentful/rich-text-types';
import {Link as GatsbyLink} from "gatsby"
// Taken from: https://www.gatsbyjs.org/docs/gatsby-link/
// If given link begins with a single `/`, treat as internal Gatsby Link
const Link = ({children, to, activeClassName, ...other}) => {
const internal = /^\/(?!\/)/.test(to);
// Use Gatsby Link for internal links, and <a> for others
if (internal) {
return (
<GatsbyLink to={to} activeClassName={activeClassName} {...other}>
{children}
</GatsbyLink>
)
}
return (
<a href={to} {...other}>
{children}
</a>
)
}
const Options = {
renderOptions: {
renderNode: {
[INLINES.HYPERLINK]: (node, next) => <Link to="${node.data.uri}">${next(node.content)}</Link>
}
}
}
export default Options
// `./gatsby-config.js`
const renderOptions = require("./components/link");
module.exports = {
// ..other config
plugins: [
{
resolve: "gatsby-source-contentful",
options: {
spaceId,
accessToken
}
}, {
resolve: '@contentful/gatsby-transformer-contentful-richtext',
options: renderOptions
},
// ..other plugins
]
}
I noticed the docs mention a custom html element like this:
[MARKS.BOLD]: text => `<custom-bold>${text}<custom-bold>`,
No closing back slash on the tag? The naming convention doesn’t suggest that it’s a React/JSX styled custom element/component, so I assume that’s not related to Gatsby/React?
I assume we’re meant to be able to at the very least integrate the Link component from Gatsby. Presently I am doing this with react-jsx-parser on the provided html string. I also have the renderOption for the plugin to create a <Link/>
element for internal links.
This isn’t full proof though, I assume parsing html elements like hr
or img
which JSX requires having closing back slashes might break it(if a documentToJSX method is made available, others elements like img
might need to be catered for).
// `./gatsby-config.js`
const { BLOCKS, MARKS, INLINES } = require('@contentful/rich-text-types')
const renderOptions = {
renderOptions: {
renderNode: {
[INLINES.HYPERLINK]: (node, next) => {
// If given link begins with a single `/`, treat as internal Gatsby Link
return /^\/(?!\/)/.test(node.data.uri)
? `<Link to="${node.data.uri}">${next(node.content)}</Link>`
: `<a href="${node.data.uri}">${next(node.content)}</a>`
}
},
},
}
module.exports = {
// ..other config
plugins: [
{
resolve: "gatsby-source-contentful",
options: {
spaceId,
accessToken
}
}, {
resolve: '@contentful/gatsby-transformer-contentful-richtext',
options: renderOptions
},
// ..other plugins
]
}
// ./some-component.js
import React from 'react'
import JsxParser from 'react-jsx-parser'
import { Link } from 'gatsby'
const RichText = (props) => (
<JsxParser
components={{ Link }}
jsx={props.content}
/>
)
Usage with example query on docs:
<RichText content={html} />
Issue Analytics
- State:
- Created 5 years ago
- Comments:8 (5 by maintainers)
Top GitHub Comments
So please forgive me as this will not only be the first github comment I’ve ever made but also the first code I will be attempting to collab on. Very nervous and not sure what proper etiquette is for working on things but I had taken a stab at this before looking at the open issues. I have been sourcing headless CMS for a family small business project and came across Contentful but also saw this need for a React transform since dangerouslySetInnerHTML limited flexibility with CSS in JS.
I looked at the code @sarahbethfederman provided but the key setting seems dangerous as it does not validate that a proper React element was passed before attempting to append the key in. This would cause text nodes to break in cases where the developer might write
[MARKS.UNDERLINE]: text => text
which would then spread your text string across your object letter by letter and add a key which would not be great. Since this is rich text, maybe a better approach is turning off underline in the CMS to avoid this but it is currently a valid callback.I also considered the case where someone might want to pass a key manually on something like the embedded asset id. I can’t think of a strong use case for this since this is again rich text and the idea is to pretty much mimic the text in the component, but it could in some crazy way be used to preserve state on a key that isn’t relying on index.
I used the built in React functions to resolve both those issues (I think) and doesn’t feel as hacky. See below:
I also reworked some of the other code to be a little more straightforward not involving the next callback (which may not be preferable in the end as it is not consistent with the other renderers, but this did however start as a personal solution to the problem). I really appreciate any feedback, especially since this is very new to me. Very excited to try to help regardless of reception. Feedback appreciated. Thanks.
index.js full repo with tests reworked from html-renderer and some changes to test React specific renders
P.S. I have never written a React test so this was a challenge and I still don’t feel like I did it right since there is so much setup involved but I ended up with snapshots that were all what I expected so hopefully that is something.
EDIT: Also worth noting that there is no need to escape the html as React does this by default hence the dangerously in ‘dangerouslySetInnerHtml’ for getting around it.
@ColeTownsend See my response and comments below on issue #46 here . Hope this helps.