question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Rendering code snippets with Gatsby

See original GitHub issue

I’m trying to include code snippets into my rich text document and render it properly formatted later on by wrapping <pre> tags around what Gatsby generates. I tried doing this:


const Blog = (props) => {
  const Code = ({children}) => <pre><code style={{backgroundColor: "red"}}>{children}</code></pre>
  const options = {
   renderMark: {
      [MARKS.CODE]: code => <Code>{code}</Code>},
  }
}

This doesn’t work though because a new <p> tag is automatically wrapped around every line of code in the rich text document, which creates invalid HTML (<pre> tags can’t be direct descendants of <p> tags) and separates each line from the others, rather than displaying the code as a block.

Am I going about this the wrong way? All I want is to include a block of code in e.g a blog post and render it in my template exactly as I typed it out in Contentful.

Would appreciate any help! Thanks

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:1
  • Comments:7

github_iconTop GitHub Comments

8reactions
sbezludnycommented, Jul 23, 2019

Hey @scirocco21 at the moment we do not natively support code blocks in the Rich Text field.

As a workaround, you can use Embedded Entry. A dedicated content type will allow specifying code metadata, like: language etc., that could be used at rendering time.

Hope this helps 😉

7reactions
johnkavanaghcommented, Mar 8, 2021

I believe there are a few problems at play here. Instead of trying to write a huge comment (although inevitably this will still be quite big), I’ve written a detailed article about it here.

First and foremost, the suggestion from @sbezludny that Contentful does not natively support code blocks in the Rich Text field is - please pardon my French - BS. For such a feature-rich - and expensive - service, I’m sure we can agree that’s not really acceptable when you consider that code bocks are made available within the Contentful interface. I would perhaps understand a little more if formatted code blocks also weren’t available there… but it is, so being able to enter content that it is then not possible to render out again is a fairly significant flaw.

Screenshot 2021-03-01 at 09 31 35

Secondly, what @scirocco21 was trying to do was a little mistaken. [MARKS.CODE] is inline code (as in: code that falls within the flow of a paragraph), not a code block. These should be wrapped in <code> and not <pre> (for what it’s worth: both of those tags are formatted as inline code). For reference, MARKS also contains BOLD, ITALIC, and UNDERLINE.

Finally, Contentful does not provide a ‘code’ block-type, which I think it an oversight on their part. What this means is that when you create a block of code in Contentful, what you are actually creating is paragraphs, with the only child inside being a ‘code’ MARK. This - I feel - is where Contentful is really letting themselves down at the moment.

To get around this, you can modify how you handle BLOCKS.PARAGRAPH. We already know that where we’ve entered a block of text into Contentful’s UI, what it has sent us is a paragraph, with a single node (normal text paragraphs will likely contain several nodes for inline elements within it), and the mark type of that first node will be ‘code’.

So, when we come to render a paragraph, instead of just outputting a <p>, we delve a little deeper to work out if it’s a code block or not, and return <pre> (and if you want: <code>) instead:

[BLOCKS.PARAGRAPH]: (node, children) => {
  if (
    node.content.length === 1 &&
    find(node.content[0].marks, { type: 'code' })
  ) {
    return <pre><code>{node.content[0].value}</code></pre>;
  }

  return <p>{children}</p>;
}

This will (very belatedly) resolve the original issue here, although it’s a workaround. There is one minor hitch - however - that that’s this: because Contentful separates these code blocks out into paragraphs first, if your code has an empty line within it, you will actually find it gets divided out into multiple <pre> sections.

Here’s a screenshot from my personal website showing you what I mean (each is wrapped in a lime outline):

Screenshot 2021-03-01 at 10 55 09

This can be countered visually with a little bit of CSS to close the gaps, but nevertheless: what you end up with isn’t semantic markup, and has other issues like odd line-wrapping and horizontal scrolling for narrower screens where you end up being forced to use white-space: pre-wrap, which isn’t ideal.

With the help of a close friend of mine (and very talented developer) Ben Stokoe, we have come up with a way of transforming Contentful’s data and bringing these adjacent code blocks together.

This comment is already a bit long to start dropping multi-line functions into, so if the above solution isn’t enough, then take a read through my article ‘Rendering Contentful Rich Conde snippets in Gatsby’ - the bigger solution is towards the bottom.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Rendering Contentful Rich Code Snippets in Gatsby
At a high level: rich content comes through as an object. Each node within the object corresponds to a block of copy (a...
Read more >
Gatsby-Contentful: Code Snippets - Tech Holding
“Gatsby is a free and open source framework based on React that ... Now your code snippets should be rendering and highlighted as...
Read more >
Render Code Snippets with Gatsbyjs and Contentful
In this post, I'll go into how to pull a code snippet from Contentful and render it within GatsbyJS with syntax highlighting.
Read more >
gatsby - How to format code snippets with <pre> tags using ...
Then, using the @contentful/rich-text-react-renderer which comes with the gatsby-source-contentful/rich-text plugin, I create a bespoke options ...
Read more >
gatsby-remark-embed-snippet
gatsby -remark-embed-snippet Embeds the contents of specified files as code snippets. Installation Note: This plugin depends on gatsby-remark…
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found