Using Webpack to Render Markdown in React Apps

By Andre Perunicic | May 2, 2018

This article is a tutorial explaining how to set up your Webpack configuration for rendering and displaying Markdown documents in React components. Something like this could come in handy if you’re building a home-made static blog engine, or if you’re hoping to easily include some good-looking documentation in a frontend application. Since I tend to write a lot of code blocks in my Markdown documents, a good chunk of the tutorial will be focused on making them look good.

After configuring your project based on the steps described below, you’ll be able to import raw Markdown documents with statements like import content from './content.md', and then automatically produce clean HTML with

<Markdown content={content} />

If you would rather jump right to the end-result of the tutorial than read through individual configuration steps, head on over to the fully-configured example project in our article materials repository. In addition to code supporting tutorials like this one, we also occasionally add interesting code snippets and useful scripts to this repo, so give it a star if you want to stay tuned.

Configuring Webpack Loaders

The two Webpack loaders that allow importing and automatically rendering Markdown documents to HTML are markdown-loader and html-loader. We’ll also make use of highlight.js, css-loader and style-loader for nice block-level code syntax highlighting.

To install the necessary requirements, use your favorite Node package manager – or just yarn.

yarn add -D markdown-loader html-loader style-loader css-loader highlight.js

Then, import highlight.js in your Webpack config

const highlight = require('highlight.js');

and add a rule like the following to enable importing and automatically rendering .md files.

{
    test: /\.(md)$/,
    use: [
      'html-loader',
      {
        loader: 'markdown-loader',
        options: {
          highlight: (code, lang) => {
            if (!lang || ['text', 'literal', 'nohighlight'].includes(lang)) {
              return `<pre class="hljs">${code}</pre>`;
            }
            const html = highlight.highlight(lang, code).value;
            return `<span class="hljs">${html}</span>`;
          },
        },
      },
    ],
  },

This highlight function handles the compilation of block-level code like

```javascript
const sayHi = () => console.log('Hello');
```

encountered in Markdown files. You can use a different syntax highlighter by customizing the highlight option of markdown-loader, but highlight.js makes it particularly easy to customize the produced code and style your code blocks with CSS. Syntax highlighting is used only when the programming language is explicitly specified with a line like ```javascript, as in the the example above. This lets you avoid errors that arise when trying to highlight languages that are not supported by highlight.js.

You may have also noticed that the .hljs class is always applied to the displayed code. This class is used by highlight.js theme CSS files, so adding it like here allows you to customize how the imported code looks simply by importing one of the theme CSS files. Be sure to check out the official highlight.js theme and language gallery.

Using Rendered Markdown in a React Component

In the introduction, I highlighted a React component that can be used to display rendered Markdown files. A full usage example can be found in the example application’s entry point:

import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';

import Markdown from './components/Markdown';
import content from './article.md';

ReactDOM.render(
  <Markdown content={content} />,
  document.getElementById('app'),
);

The component itself is just as simple:

import React from 'react';

import './gruvbox-dark.css';
import './markdown.css';

const wrapMarkup = html => ({
  __html: html,
});

const Markdown = ({ content }) => (
  <div className="markdown" dangerouslySetInnerHTML={wrapMarkup(content)} />
);

export default Markdown;

The first of the two CSS imports can be downloaded from the official highlight.js repository and will cause syntax highlighted code blocks to use the dark version of the Gruvbox theme, which you can see on this page. The second CSS import is where you can customize the HTML produced by rendering your Markdown files. In the example project, I’ve customized the way tables are rendered so that they have alternating color rows. In general, Markdown is rendered as undecorated HTML, so you can easily customize its appearance via basic selectors prefixed by .markdown, e.g., .markdown table or .markdown pre. Head on over to the example project to see the end-result in action.

While we sometimes add tutorials like this to the Intoli blog, most of our articles are in-depth pieces about technical topics surrounding browser automation, DevOps, JavaScript development, and others. If you’d like to get just the latest and greatest every month, consider subscribing to our mailing list!

The Intoli Monthly Newsletter

Enjoying this article? Sign up to get monthly updates on our best new content!

Suggested Articles

If you enjoyed this article, then you might also enjoy these related ones.

Building a YouTube MP3 Downloader with Exodus, FFmpeg, and AWS Lambda

By Evan Sangaline
on May 21, 2018

A short guide to building a practical YouTube MP3 downloader bookmarklet using Amazon Lambda.

Read more

Running FFmpeg on AWS Lambda for 1.9% the cost of AWS Elastic Transcoder

By Evan Sangaline
on May 2, 2018

A guide to building a transcoder using Exodus, FFmpeg, and AWS Lambda.

Read more

Using Ant Design in Sass-Styled Projects

By Andre Perunicic
on April 24, 2018

Introducing antd-scss-theme-plugin, an easy way to use Ant Design with SCSS.

Read more

Comments