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
.
Follow the
create-react-app
getting started steps to create your initial appSet 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; } };
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);
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}`); });
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 }); }
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.