Skip to content

Using Markdoc with React

Markdoc supports rendering Markdoc syntax with React out-of-the-box.

To get started with React, check out this example repo for how to use Markdoc with create-react-app and express.

Setup

Follow these steps to build a Markdoc app with create-react-app and express.

  1. Follow the create-react-app getting started steps to create your initial app

  2. Set up a Markdoc schema

    schema/ ├── Callout.markdoc.js └── heading.markdoc.js 
    // [schema/Callout.markdoc.js](https://github.com/markdoc/docs/blob/dcba1a62be92097e3fd50c21e05fd6d2ea709312/examples/react-nodejs/schema/Callout.markdoc.js#L1-L18) module.exports = { render: 'Callout', children: ['paragraph', 'tag', 'list'], attributes: { type: { type: String, default: 'note', matches: ['check', 'error', 'note', 'warning'] } } }; 
    // [schema/heading.markdoc.js](https://github.com/markdoc/docs/blob/dcba1a62be92097e3fd50c21e05fd6d2ea709312/examples/react-nodejs/schema/heading.markdoc.js#L1-L22) const { nodes } = require('@markdoc/markdoc'); function generateID(children, attributes) { if (attributes.id && typeof attributes.id === 'string') { return attributes.id; } return children .filter((child) => typeof child === 'string') .join(' ') .replace(/[?]/g, '') .replace(/\s+/g, '-') .toLowerCase(); } module.exports = { ...nodes.heading, transform(node, config) { const base = nodes.heading.transform(node, config); base.attributes.id = generateID(base.children, base.attributes); return base; } }; 
  3. Parse your Markdoc documents on the server

    // [...](https://github.com/markdoc/docs/blob/main/examples/react-nodejs/createContentManifest.js#L13) const rawText = fs.readFileSync(file, 'utf-8'); const ast = Markdoc.parse(rawText); 
  4. Call Markdoc.transform on the server

    // [server.js](https://github.com/markdoc/docs/blob/main/examples/react-nodejs/server.js) const express = require('express'); const app = express(); const callout = require('./schema/callout.markdoc'); const heading = require('./schema/heading.markdoc'); // [...](https://github.com/markdoc/docs/blob/dcba1a62be92097e3fd50c21e05fd6d2ea709312/examples/react-nodejs/server.js#L8-L14) app.get('/markdoc', (req, res) => { const ast = contentManifest[req.query.path]; const config = { tags: { callout }, nodes: { heading }, variables: {} }; const content = Markdoc.transform(ast, config); return res.json(content); }); app.listen(4242, () => { console.log(`Example app listening on port ${4242}`); }); 
  5. Call Markdoc.renderers.react on the client

    // src/App.js import React from 'react'; import Markdoc from '@markdoc/markdoc'; import { Callout } from './Callout'; export default function App() { const [content, setContent] = React.useState(null); React.useEffect(() => { (async () => { const response = await fetch( `/markdoc?` + new URLSearchParams({ path: window.location.pathname }), { headers: { Accept: 'application/json' } } ); if (response.status === 404) { setContent('404'); return; } const content = await response.json(); setContent(content); })(); }, []); if (content === '404') { return <p>Page not found.</p>; } if (!content) { return <p>Loading...</p>; } const components = { Callout }; return Markdoc.renderers.react(content, React, { components }); } 
  6. Start up the client and server

    npm run start:client 

    and

    npm run start:server 


Or, clone this starter repo and follow the directions in the README.