Phases of rendering
Markdoc has three phases of rendering: parse
, transform
, and render
. Each phase operates on the output of the previous phases.
Markdoc also includes a validate
function, that you can run separately from the render phases to confirm the Markdoc document is valid.
See the validation docs for more info.
Parse
parse(string) => AstNode
Parse transforms a raw string into an abstract syntax tree (AST) representing your Markdoc document. The AST contains information about your content, including where each piece of content exists within the document.
An example AST would look like this:
{ "type": "document", "attributes": {}, "children": [ { "type": "paragraph", "attributes": {}, "children": [...], "lines": [0, 2], "location": { "start": { "line": 0 }, "end": { "line": 2 } }, "errors": [], "inline": false, } ], "lines": [], "errors": [], "inline": false }
Check this out for yourself in the developer playground.
AST node instances also include helpful functions, like walk
, which can be useful for traversing and mutating your AST.
const ast = Markdoc.parse(document); for (const node of ast.walk()) { // do something with each node }
Transform
transform(AstNode | AstNode[], ?Config) => RenderableTreeNode | RenderableTreeNode[]
Transform takes an abstract syntax tree and transforms it into a renderable tree, a serializable intermediate representation of what will eventually be rendered. This object is useful for computing things like a table of contents, or passing over the wire to your client.
The transform step is also responsible for resolving variables into static, scalar values (string, boolean, object, and so on.).
An example renderable tree will look like this:
{ "name": "article", "attributes": {}, "children": [ { "name": "h1", "attributes": {}, "children": ["Header"], "$$mdtag": true } ], "$$mdtag": true }
You can see a more advanced renderable tree in the developer playground.
Render
Render takes in a renderable tree and converts it into rendered output. For html
, that means creating an HTML document as a string. For react
, it means creating a React element.
You can create your own renderer by creating a function that takes in a renderable tree as a parameter and returns your desired output.
An example html
output would look like this:
<h1>Getting started</h1> <p>Run this command to install the Markdoc library:</p>
React
renderers.react(RenderableTreeNode | RenderableTreeNode[]) => React.Node
Markdoc supports rendering React out-of-the-box. You can see the React renderer in action in the developer playground.
To render React, first create a renderable tree from your document calling transform
. You can do this from the server or client.
const tags = { callout: { render: 'Callout', attributes: {} } }; const doc = ` {% callout %} Attention, over here! {% /callout %} `; const ast = Markdoc.parse(doc); const content = Markdoc.transform(ast, { tags });
Then, call Markdoc.renderers.react
with the renderable tree from your client application. Along with content
and React
, you'll need to provide the components
object as an argument. The components
object specifies a mapping from your tags and nodes to the corresponding React component.
import Markdoc from '@markdoc/markdoc'; import React from 'react'; // or 'preact' function Callout({ children }) { return <div className="callout">{children}</div>; } function MyApp() { return Markdoc.renderers.react(content, React, { components: { Callout: Callout } }); }
Rendered output
Attention, over here!
HTML
renderers.html(RenderableTreeNode | RenderableTreeNode[]) => string
Markdoc supports rendering HTML out-of-the-box. Because the HTML renderer outputs your HTML document as a string, you can use Web Components with no extra configuration.
To render HTML, first create a renderable tree from your content by calling transform
:
const doc = ` # Getting started Run this command to install the Markdoc library: `; const ast = Markdoc.parse(doc); const content = Markdoc.transform(ast);
Then, call Markdoc.renderers.html
with your renderable tree, which will create the corresponding HTML document.
const express = require('express'); const Markdoc = require('@markdoc/markdoc'); const app = express(); app.get('/docs/getting-started', (req, res) => { res.setHeader('Content-Type', 'text/html'); res.send(` <!DOCTYPE html> <html> <body> ${Markdoc.renderers.html(content)} </body> </html> `); });
<!DOCTYPE html> <html> <body> <h1>Getting started</h1> <p>Run this command to install the Markdoc library:</p> </body> </html>
Create your own
Because Markdoc renderers are regular functions, you can create a custom one for whatever your use case requires.
Try creating your own for Vue, Svelte, Spectacle, or anything else you can think of.