Nodes
Nodes are elements that Markdoc inherits from Markdown, specifically the CommonMark specification. 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
You define custom nodes by passing a custom Node to your config
object, like:
import { heading } from './schema/Heading.markdoc'; import * as components from './components'; /** @type {import('@markdoc/markdoc').Config} */ 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 |