How do I load a markdown file into a react component?

ReactjsMarkdown

Reactjs Problem Overview


How would I load a .md markdown file into a react component? I have tried so many npm libraries through google searches and I cant find a good solution.

Code image

I want to load the .md file something like:

render() {
    <div>
        <MarkDown src="about.md" />
    </div>
}

Reactjs Solutions


Solution 1 - Reactjs

I use marked (GitHub).

I first import it like this:

import marked from "marked";

I then fetch my *.md file within React's componentDidMount event and store it in my component's state using marked(text) (where text is the response):

componentDidMount() {
  const readmePath = require("./Readme.md");

  fetch(readmePath)
    .then(response => {
      return response.text()
    })
    .then(text => {
      this.setState({
        markdown: marked(text)
      })
    })
}

...and finally I render it on the page using the dangerouslySetInnerHTML attribute:

render() {
  const { markdown } = this.state;

  return (
    <section>
      <article dangerouslySetInnerHTML={{__html: markdown}}></article>
    </section>
  )
}

Solution 2 - Reactjs

A full working example with react-markdown:

import React, { Component } from 'react'
import ReactMarkdown from 'react-markdown'
import termsFrPath from './Terms.fr.md'

class Terms extends Component {
  constructor(props) {
    super(props)

    this.state = { terms: null }
  }

  componentWillMount() {
    fetch(termsFrPath).then((response) => response.text()).then((text) => {
      this.setState({ terms: text })
    })
  }

  render() {
    return (
      <div className="content">
        <ReactMarkdown source={this.state.terms} />
      </div>
    )
  }
}

export default Terms

Solution 3 - Reactjs

You should use react-markdown instead of the accepted answer, this solution doesn't use dangerouslySetInnerHTML.

App.js

import React, { Component } from 'react';
import AppMarkdown from './App.md';
import ReactMarkdown from 'react-markdown';

class App extends Component {

  constructor() {
    super();
    this.state = { markdown: '' };
  }

  componentWillMount() {
    // Get the contents from the Markdown file and put them in the React state, so we can reference it in render() below.
    fetch(AppMarkdown).then(res => res.text()).then(text => this.setState({ markdown: text }));
  }

  render() {
    const { markdown } = this.state;
    return <ReactMarkdown source={markdown} />;
  }
}

export default App;

App.md

# React & Markdown App
* Benefits of using React... but...
* Write layout in Markdown!

Solution 4 - Reactjs

markdown-to-jsx provides very efficeint functionality to interact with markdown in React component.

It allows replacing/overriding of any HTML element with your Custom Component for markdown, here is the doc.

import React, { Component } from 'react'
import Markdown from 'markdown-to-jsx';
import README from './README.md'

class PageComponent extends Component {
  constructor(props) {
    super(props)

    this.state = { md: "" }
  }

  componentWillMount() {
    fetch(README)
      .then((res) => res.text())
      .then((md) => {
        this.setState({ md })
      })
  }

  render() {

    let { md } = this.state

    return (
      <div className="post">
        <Markdown children={md}/>
      </div>
    )
  }
}

export default PageComponent
Edit 2nd Aug'21
Functional Component
const PageComponent = ()=> {

    let [ content, setContent] = useState({md: ""});

    useEffect(()=> {
        fetch(README)
            .then((res) => res.text())
            .then((md) => {
                setContent({ md })
            })
    }, [])

    return (
      <div className="post">
        <Markdown children={content.md}/>
      </div>
    )
}

Solution 5 - Reactjs

Similar to @Xing-Han-Lu's answer but with react Markdown. The concept uses useEffect to load up the file then adds it to state using the useState hook where it's accessible to reactMarkdown

import React, { useState, useEffect } from "react";
import ReactMarkdown from "react-markdown";
import file from "./md/posts.md";

export default function () {
  const [markdown, setMarkdown] = useState("");

  useEffect(() => {
    fetch(file)
      .then((res) => res.text())
      .then((text) => setMarkdown(text));
  }, []);

  return (
    <>
      <ReactMarkdown source={markdown} />
    </>
  );
}

Solution 6 - Reactjs

Approach using webpack loader

Install raw-loader

npm install raw-loader --save-dev

Update webpack.config.js

module.exports = {
  //...
  module: {
    rules: [
      // ...
      {
        test: /\.md$/,
        use: "raw-loader",
      },
    ],
  },
};

Create markdown file (say App.md)

# React & Markdown App

- Benefits of using React... but...
- Write layout in Markdown!

Import App.md and use it in React component.

import React from "react";
import ReactMarkdown from 'react-markdown';
import AppMarkdown from './App.md';

function App() {
  return (
    <div>
      <ReactMarkdown children={`${AppMarkdown}`} />
    </div>
  );
}

export default App;

Solution 7 - Reactjs

For Typescript + react please follow below steps:

  1. Create one type definition (index.d.ts) file in one of the project directory and put the following code.
declare module "*.md";
  1. Add tsconfig.json -> CompilerOptions -> typeRoots as following
{
     "compilerOptions": {
         ...
         "typeRoots": [ "<types-directory-created-in-#1>", "./node_modules/@types"],
         ...
     }
}
  1. Install two libraries showdown and html-react-parser

yarn add showdown or npm install showdown

yarn add html-react-parser or npm install html-react-parser

  1. In your component
import React, { useEffect, useState } from 'react';
import showdown from 'showdown';
import parse from 'html-react-parser';
import readme from 'path/filename.md';

export default function ComponentName() {
    const [html, setHTML] = useState("");

    //Use componentDidMount(): if class based component to load md file
    useEffect(() => {
        fetch(readme)
            .then(data => data.text())
            .then(text => {
                const converter = new showdown.Converter();
                setHTML(converter.makeHtml(text));
            })
    }, []);

    return (
        <div>{parse(html)}</div>
    )
}

Solution 8 - Reactjs

I slightly modified this solution to use hooks and useEffect (which is different from componentWillUpdate but still works). If you built your app with create-react-app and you have a markdown document called document.md, you can build your app in the following way:

import { useState, useEffect } from 'react';
import Markdown from 'markdown-to-jsx';
import mdDocument from './document.md';

const App = () => {
  const [content, setContent] = useState("");

  useEffect(() => {
    fetch(mdDocument)
      .then(res => res.text())
      .then(md => { setContent(md) })
  })

  return (
    <div><Markdown children={content} /></div>
  )
}

export default App;

Solution 9 - Reactjs

Where I struggled with all these answers is the loading of the markdown file into frontend React. They make some kind of assumption as to what you're using.

For the world of React I would recommend MDX.

I'm using it with Next.js, but MDX is compatible with lots of Javascript bundlers and React libraries and does a lot of work to handle the bit that lots of people ignore here which is the loading in of non-JS syntax.

> Note: MDX sticks more to the original style of Markdown without tables or the funky extras. If you want extra stuff you need to install MDX plugins

See these references:

Install with:

npm install @next/mdx @mdx-js/loader

next.config.js:

For Next.js integration we don't have to touch the webpack config just wrap our existing next.config.js with a withMDX function:

/**
 * @link https://github.com/vercel/next.js/tree/canary/packages/next-mdx#usage
 */
const withMDX = require('@next/mdx')()

// your existing next.config.js
const nextConfig = {
   ...
}

module.exports = withMDX(nextConfig)

about.mdx:

Read more about this in Using MDX docs

# Just some regular markdown

any old rubbish **will do**

You can stick extra <Funky /> stuff in here but *regular markdown* works fine

AboutPage.jsx:

Note below how now you don't need to do any fetching or useEffect, it's simply like loading in a JSON or JS file.

import React from "react";
import AboutMarkdown from "./about.mdx";

const AboutPage () => (
    <AboutMarkdown />
);

Solution 10 - Reactjs

If you use Webpack (i.e. Electron React Boilerplate) then you can save a few steps by using Webpack loaders.

npm i -D html-loader markdown-loader marked

In webpack.config.renderer.dev.js:

import marked from 'marked';
const markdownRenderer = new marked.Renderer();

....

  // Markdown
  {
    test: /\.md$/,
    use: [
      {
        loader: 'html-loader'
      },
      {
        loader: 'markdown-loader',
        options: {
          pedantic: true,
          renderer: markdownRenderer
        }
      }
    ]
  }

Then, in the React component it's simply a require and setting the HTML.

import knownIssues from '../assets/md/known-issues.md';
....
<p dangerouslySetInnerHTML={{ __html: knownIssues }} />

Lastly, Flow will report an error (it still works) when importing the markdown file. Add this to .flowconfig to make Flow treat md files as string assets (care of Webpack):

module.name_mapper.extension='md' -> '<PROJECT_ROOT>/internals/flow/WebpackAsset.js.flow'

Solution 11 - Reactjs

I have tried the above suggestions and deduced that after running a command

> npm install markdown
import ReactMarkdown from 'markdown';

it finally worked for me

Solution 12 - Reactjs

I wanted it to work using dynamic imports using react-markdown. My general code is below, you'll have to add a useEffect to call the function and put a reference to the state variable in the function return:

  const [displayElement, setDisplayElement] = useState(null);

  //Get markdown file
  const fetchMarkdown = async (location) => {
    console.log("MD location: ", location);
    try {
      //I figured out readmePath.default using print statements, left there in case
      //someone wants them
      const readmePath = await require("" + location);
      //console.log(readmePath);
      const response = await fetch(readmePath.default);
      //console.log("response => ", response);
      const text = await response.text();
      //console.log(text);

      // the state variable I am setting the markdown into, in my render function 
      // I have {displayElement}.
      setDisplayElement(
        <div className={styles.markdownContainer}>
          <ReactMarkdown children={text} />
        </div>
      );
    } catch (e) {
      console.log("Markdown file: couldn't read =>", location, e);
    }
  };

The addition of the empty string in const readmePath = await require("" + location); is required (hehe). I got that from here. I don't know why it works.

Solution 13 - Reactjs

Another option is to put the Markdown in a .js file, using the backtick ` character to enclose the Markdown as an untagged template literal. Like this:

const MD = `
**TERMS OF SERVICE**

Last Modified: 30 November 2021...`

export default MD

Then you can import it like any other module.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPizzaHeadView Question on Stackoverflow
Solution 1 - ReactjsJames DonnellyView Answer on Stackoverflow
Solution 2 - ReactjsDorianView Answer on Stackoverflow
Solution 3 - ReactjsKevinView Answer on Stackoverflow
Solution 4 - ReactjsNishchitView Answer on Stackoverflow
Solution 5 - ReactjsRiunge MainaView Answer on Stackoverflow
Solution 6 - ReactjsVladView Answer on Stackoverflow
Solution 7 - ReactjsPramod MaliView Answer on Stackoverflow
Solution 8 - ReactjsxhluluView Answer on Stackoverflow
Solution 9 - Reactjsicc97View Answer on Stackoverflow
Solution 10 - ReactjsCaylan Van LarsonView Answer on Stackoverflow
Solution 11 - ReactjsOtabek ButcherView Answer on Stackoverflow
Solution 12 - ReactjsThomas SloanView Answer on Stackoverflow
Solution 13 - Reactjsed94133View Answer on Stackoverflow