DEV Community

James Wallis
James Wallis

Posted on • Updated on

How to use the Remark Markdown converters with Next.js projects

Next.js is a React.js framework for server side rendering and static projects. It's easy to use and works extremely well when building a website which stores its content in Markdown. A feature called dynamic routes, which generates routes at build time, provides functionality to read a directory full of Markdown files and generate separate webpages for each file.

Remark-react is a package that converts Markdown into React and it works with a Next.js application. It differs from remark-html as it doesn't force the developer to use dangerouslySetInnerHTML.

Honestly, if you're wanting to use Markdown with Next.js I'd recommend you try out remark-react. If you do, you should also be aware of the following:

Remark-react will create all links using the <a> component whereas in Next.js you should be using the <Link> component from next/link.

Using the proper <Link> component in a Next.js project is important as it changes the content of the page and the URL without a full redirect, whereas when an anchor (<a>) tag is used the page will be reloaded and React will need to do a full render - this can cause your application to perform badly and appear slow.

 Configuring a Next.js application to use remark-react, properly

The example is taken from GitHub

Adding Markdown to React conversion

printMarkdown.js on GitHub

You'll need three NPM packages:

npm i -s unified remark-parse remark-react
Enter fullscreen mode Exit fullscreen mode

Once you've added them, import them all into your React app:

import unified from 'unified';
import parse from 'remark-parse';
import remark2react from 'remark-react';
Enter fullscreen mode Exit fullscreen mode

Next, add the following code to convert Markdown into React components:

const content = unified()
    .use(parse)
    .use(remark2react)
    .processSync(markdown).result;
Enter fullscreen mode Exit fullscreen mode

From the code blocks above, your Next.js application should now be rendering Markdown into React.

Adding a CustomLink to handle local and external linking

Now we can add a custom link component to the remark-react configuration to instruct it to use the <Link> component for local links and the <a> component for external links.

customLink.js on GitHub

Add a new component called customLink.js to your project with the contents:

import Link from 'next/link';

export default function CustomLink({ children, href }) {
  // If the link is local it will start with a "/"
  // Otherwise it'll be something like "https://"
  return href.startsWith('/') || href === '' ? (
    <Link href={href}>
      <a>
        {children}
      </a>
    </Link>
  ) : (
    <a
      href={href}
      target="_blank"
      rel="noopener noreferrer"
    >
      {children}
    </a>
  );
}
Enter fullscreen mode Exit fullscreen mode

The CustomLink component will render a <Link> if the href passed in has a local target such as /about but will render an <a> if it has an external target such as https://dev.to.

 Updating the Markdown converter to use the CustomLink component

Finally, we need to update the Markdown to React code to use the CustomLink component when rendering links. This can be done by adding a configuration object to the remark-react .use line:

  const content = unified()
    .use(parse)
    .use(remark2react, {
      remarkReactComponents: {
        // Use CustomLink instead of <a>
        a: CustomLink,
      },
    })
    .processSync(markdown).result;
Enter fullscreen mode Exit fullscreen mode

Summary

That's all you need to do to use React-remark in your Next.js project. Using the configuration object, you can add a custom component for more than just an anchor HTML tag, incase you want to swap the img tag for something more intelligent (image compression?) for example.

Drop me a reaction or comment if this has helped you.
Thanks for reading!

Top comments (9)

Collapse
 
slumbering profile image
Blocksmith

Hello :)

For info about Remark-react :
🚨 Stability: Legacy. This package is no longer recommended for use. It’s still covered by semantic-versioning guarantees and not yet deprecated, but use of this package should be avoided. Please use remark-rehype to move from remark (markdown) to rehype (HTML) and then replace remark-react with rehype-react.

Collapse
 
adamreinmuller profile image
Adam Reinmuller

Dude I can't thank you enough for this article and the attached repo.
My guesstimate is that you saved me 20 hours at least... especially using the CustomLink method.
Cheers

Collapse
 
jameswallis profile image
James Wallis

Buzzing that the article helped, thanks!

Collapse
 
sanjib104 profile image
SANJIB KUMAR DEY

Man, this helped a ton !!!
Been scurrying around for last few hours just to figure this out.
On point solution, thanks !!!

Collapse
 
jameswallis profile image
James Wallis

Thank you!

Collapse
 
sanjib104 profile image
SANJIB KUMAR DEY

Hey James, could you help me out with syntax highlighting with remark markdown.
It is failing to highlight the code.

Collapse
 
jameswallis profile image
James Wallis

Hi Sanjib, did you add the CSS stylesheet to your _app.js?

github.com/james-wallis/wallis.dev...

Collapse
 
sanjib104 profile image
SANJIB KUMAR DEY

Hey James, I tried that as well.
I followed up your recent blog update. Could see you've dropped remark-to-react.
Any way to workaround it ? That external link target config was quite easy with that library.
Here's my repo: github.com/sanjibdey104/webdevref/...
Would be great if you can check the code once.

(on the main branch I've user react-markdown and react-syntax-highlighter, though there's one small glitch - nothing breaking)

Thread Thread
 
jameswallis profile image
James Wallis

Hi, oh yeah sorry. I can't remember getting syntax highlighting working with React Remark, can't even recall trying.

I'd check that the CSS classnames are being added on the client side, that'll narrow down whether it's the CSS that isn't working or the converter. Do you want to send me a link to your site with some content that should be highlighted?