A guide to building interactive documents with Markdoc.

Markdoc is the document format powering Stripe's world-class documentation pages. It is similar to MDX in that it offers a combination of Markdown and components, but in a slightly different way that enforces a more strict separation between content and code. With Motif, you can now author Markdoc pages straight from the browser:

Markdoc example in Motif

You can easily get started publishing Markdoc, for instance by duplicating the above example from the Community pages.

View sample

Creating a Markdoc

In order to create a page that uses the Markdoc format, simply add the .mdoc extension to your filename.


You are free to mix Markdoc with MDX throughout your project.


In Motif, the Markdoc configuration should be stored in a file named markdoc.config.js at the root of your project source. It adheres to the ES module syntax, and should export a default value holding the config object. Here is an example:

// markdoc.config.js
const config = {
nodes: {
heading: {
render: 'Heading',
attributes: {
id: { type: String },
level: { type: Number }
tags: {
callout: {
render: 'Callout',
attributes: {
title: {
type: String,
description: 'Top callout title'
variables: {
name: 'Dr. Mark',
frontmatter: {
title: 'Configuration options'
functions: {
includes: {
transform(parameters, config) {
const [array, value] = Object.values(parameters);
return Array.isArray(array)
? array.includes(value)
: false;
export default config


Components, as referenced from the Markdoc config's nodes and tags entries, should be exported from a file named markdoc.components.js, as the default export. It is also adhering to the ES module syntax, and can freely import components and variables from other places in the project, or from the web. Here is an example:

// markdoc.components.js
import { Note } from ""
import { HeadingWrapper } from "@components/wrappers"
export const Heading = ({ id, children }) => {
return <HeadingWrapper id={id}>{ children }</HeadingWrapper>
export default {
Callout: Note,


Partials are not currently supported. Instead, we recommend using the same powerful Template mechanism that is used throughout for all pages.