Nodes
Markdoc nodes enable you to customize how your document renders without using any custom syntax—it consists entirely of Markdown. Customizing nodes lets you extend your implementation incrementally.
Built-in nodes
Markdoc comes out of the box with built-in nodes for each of the CommonMark types:
Node type | Attributes | ||||||
---|---|---|---|---|---|---|---|
document | frontmatter | ||||||
heading | level | ||||||
paragraph | — | ||||||
hr | — | ||||||
|
| ||||||
fence |
| ||||||
blockquote | — | ||||||
list | ordered | ||||||
item | — | ||||||
table | — | ||||||
thead | — | ||||||
tbody | — | ||||||
tr | — | ||||||
|
| ||||||
|
| ||||||
inline | — | ||||||
strong | — | ||||||
em | — | ||||||
s | — | ||||||
|
| ||||||
code | content | ||||||
text | content | ||||||
hardbreak | — | ||||||
softbreak | — | ||||||
error | — |
Customizing Markdoc nodes
Nodes are elements that Markdoc inherits from Markdown, specifically the CommonMark specification.
You define custom nodes by passing a custom Node to your Config
, like:
import { heading } from './schema/Heading.markdoc'; import * as components from './components'; const config = { nodes: { heading } }; const ast = Markdoc.parse(doc); const content = Markdoc.transform(ast, config); const children = Markdoc.renderers.react(content, React, { components });
where heading
looks something like:
// ./schema/Heading.markdoc.js import { Tag } from '@markdoc/markdoc'; // Or replace this with your own function 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(); } export const heading = { children: ['inline'], attributes: { id: { type: String }, level: { type: Number, required: true, default: 1 } }, transform(node, config) { const attributes = node.transformAttributes(config); const children = node.transformChildren(config); const id = generateID(children, attributes); return new Tag( `h${node.attributes['level']}`, { ...attributes, id }, children ); } };
After registering this custom node, you can then use it in your Markdoc, like:
#### My header
Options
These are the optional fields you can use to customize your Node
:
Option | Type | Description |
---|---|---|
render | string | Name of the output (for example, HTML tag, React component name) to render |
children | string[] | Determines which tag or node types can be rendered as children of this node. Used in schema validation. |
attributes | { [string]: SchemaAttribute } | Determines which values (and their types) can be passed to this node. |
transform | (Ast.Node, ?Options) => | RenderableTreeNode | RenderableTreeNode[] | null | Customize the Markdoc transform function for this node, returning the custom output you want to eventually render. This is called during the transform step. |
validate | (Node, ?Options) => ValidationError[]; | Extend Markdoc validation. This validates that the content meets validation requirements, and is called during the validate step |