Templates
MDX authoring guide
Minimal, end-to-end reference for writing new MDX documentation pages in the Datamotive docs system — frontmatter, file rules, components, workflow, and a copy-paste page template.
- Product
- Datamotive Platform
- Version
- v2.0.3
- Documentation status
- Draft
- Last updated
- Updated
- Reading time
- 7 min read
This guide is the short, practical reference for writing any docs page in src/content/docs/. Pair it with the MDX component placeholders page when you need ready-to-paste snippets for each component.
Part 1 — What MDX gives you
MDX is Markdown plus React components. You write prose as normal Markdown, and where you need a callout, a tab group, a step list, or a table with badges you drop a component in directly:
This is a normal paragraph with **bold** and `code`.
<Callout type="warning" title="Watch out">
Components live right next to your prose. No imports needed.
</Callout>Every component in this repo is globally registered — you never write import statements in an MDX file.
When to use .mdx vs .md:
.mdx— every page undersrc/content/docs/.md— repo-level files only (README.md,CHANGELOG.md,.github/templates)
Part 2 — File layout
Pages live under src/content/docs/, organised by product or section:
src/content/docs/
_templates/ ← internal authoring references (this guide lives here)
getting-started/ ← onboarding
core/ ← platform concepts shared across products
dr/ ← Disaster Recovery
migrate/ ← Migration
protect/ ← Protection
backup/ ← Backup
kb/ ← knowledge base / troubleshooting
resources/ ← whitepapers, videos, external links
partners/ ← partner program pagesThe URL is the folder path. A file at src/content/docs/dr/workflows/failover.mdx renders at /docs/dr/workflows/failover. There is no slug field in frontmatter — the path is the slug.
File name rules:
| Rule | Correct | Wrong |
|---|---|---|
| Lowercase | failover.mdx | Failover.mdx |
| Hyphens, not underscores | protection-plans.mdx | protection_plans.mdx |
| No spaces | quick-start.mdx | quick start.mdx |
| Descriptive | cli-reference.mdx | page1.mdx |
Where to put images:
public/docs/images/[section]/your-image.pngReference them as /docs/images/[section]/your-image.png — always absolute, never relative.
Part 3 — Frontmatter
Every page starts with a YAML block between two --- fences:
---
title: "Failover"
description: "Promote the target site, validate workloads, and cut over traffic during a planned or emergency failover."
section: "Disaster Recovery"
category: "Workflows"
product: "Datamotive Platform"
version: "2.0.3"
status: "published"
sidebar_position: 1
tags:
- failover
- workflow
- dr
keywords:
- promote target site
- failover steps
last_updated: "2026-05-27"
---| Parameter | Type | Required | Description |
|---|---|---|---|
| title | string | required | Page title. Rendered as the H1, the browser tab title, and the sidebar label. Keep under 60 characters. |
| description | string | required | One-to-two sentence summary. Used in search results and social previews. Keep under 160 characters. |
| section | string | required | Top-level navigation section. Must match an entry in src/content/docs/_config.ts. |
| category | string | required | Sub-section within the section. Must match an entry in _config.ts. |
| product | string | required | Owning product. Use "Datamotive Platform" unless a product-specific value applies. |
| version | string | required | Solution version the page documents. Use "2.0.3" for current docs — keep this consistent across all pages. |
| status | string | required | Publishing status: draft, review, or published. |
| sidebar_position | integer | required | Sort order within the category. Lower numbers appear higher. |
| tags | string[] | optional | Lowercase, hyphenated tags for filtering and related-content logic. 3–6 per page. |
| keywords | string[] | optional | Extra search phrases not already in the title or description. |
| last_updated | string | required | ISO date of the last substantive edit: YYYY-MM-DD. |
Part 4 — Page structure rules
Every page follows the same shape:
---
[frontmatter]
---
[intro paragraph — no heading, 1–3 sentences]
## First H2 section
...
## Second H2 section
...Heading hierarchy: Use ## (H2) for major sections, ### (H3) for sub-sections, #### (H4) sparingly. Never skip from H2 to H4. H2 headings appear in the right-rail table of contents.
Common markdown:
**Bold** for UI labels and key terms.
*Italic* for file names, titles, and new terms on first use.
`inline code` for flags, paths, config keys.
~~Strikethrough~~ for deprecated terms.
- Unordered list when sequence doesn't matter
- Nested item (two-space indent)
1. Ordered list when sequence matters
2. For multi-step procedures, prefer <Steps> instead
[Internal link](/docs/getting-started/quick-start) ← always absolute /docs/ path
<ExternalLink href="https://example.com">External</ExternalLink> ← never bare <a>Code blocks must have a language tag (bash, powershell, typescript, python, go, yaml, json, sql, text, mdx, html, css):
```bash
systemctl status dm-mgmt
```Part 5 — Component catalog
Every component below is globally available — just use the tag. For ready-to-paste examples of each one, open the MDX component placeholders page.
| Component | Use it for |
|---|---|
<Callout> | Inline boxes — variants: info, note, tip, success, warning, error, prerequisite, security, configuration. |
<MinimumVersionCallout> | Flag a section that needs a minimum product version. |
<UnsupportedPlatformCallout> | Warn that a feature does not work on a given platform. |
<RequirementCallout> | List prerequisites at the top of a guide or tutorial. |
<Steps> | Numbered procedure with a visual guide rail. Use for any multi-step task. |
<Tabs> | Group OS, language, or mode variants of the same content. |
<CodeGroup> | Tabbed code-only block when only the code differs across languages. |
<TerminalCommand> | Single shell command with a copy button and $ prompt. |
| [object Object][object Object] | Linked tiles guiding readers to related pages. |
<ButtonLink> | Call-to-action link styled as a button. |
| [object Object][object Object] | Inline status chips (GA, beta, deprecated, required, version). |
<ParameterTable> | API or CLI parameter reference (name, type, required, default, description). |
<SupportMatrixTable> | Platform capability matrix with badge cells. |
<CompatibilityTable> | Source/target compatibility grid. |
<FeatureComparisonTable> | Edition or tier feature comparison. |
<StatusTable> | Lifecycle or release-stage tables. |
<TroubleshootingTable> | Symptom → cause → action grid. |
<RequirementsTable> | Hardware, network, and software prerequisites. |
<GlossaryTable> | Term-definition pairs. |
<DocsTable> | General-purpose table when no named table fits — supports React cells. |
<APIEndpoint> | Method + path chip placed above the parameters table. |
<FileTree> | Visual directory layout with folder and file icons. |
<ResponsiveImage> | Full-width screenshot or diagram. |
<FigureWithCaption> | Image plus a caption that carries information. |
<ImageEmbed> | Inline raster image with width controls. |
<ArchitectureDiagram> | Placeholder or rendered architecture diagram block. |
<YouTubeEmbed> | Embed a YouTube walkthrough by video ID. |
<VideoEmbed> | Self-hosted video with poster image. |
<ExternalLink> | Always use for third-party URLs — adds icon, target, rel attributes. |
<RelatedDocs> | Curated list of related docs pages at the end of a page. |
<NextSteps> | Recommended next-action block after a tutorial. |
| NaN | Optional inline metadata strips (most pages do not need these). |
| [object Object][object Object] | LaTeX math for reference pages — see Math components in placeholders. |
Component usage rules at a glance
- Every
<Tabs>needslabel="..."— accessibility requirement. - Every
<Step>needstitle="..."— verb-phrase, short. - Every image needs
alt="..."— describe what the image shows, under 125 characters. - One
<Callout>per topic — do not stack callouts back to back; fold into prose instead. - Use the most specific table component that fits —
<DocsTable>only when none of the named ones do. - Always wrap external URLs in
<ExternalLink>— never bare<a>or plain[text](https://...).
Part 6 — Page template (copy this)
Open a new file under src/content/docs/[section]/, paste this template, and replace every [PLACEHOLDER]. Sections you don't need can be deleted — keep the order of the ones you do keep.
---
title: "[Page title — under 60 chars, primary keyword near the start]"
description: "[1–2 sentence summary, under 160 chars. What will the reader find and do?]"
section: "[Section label — must match _config.ts]"
category: "[Category label — must match _config.ts]"
product: "Datamotive Platform"
version: "2.0.3"
status: "draft"
sidebar_position: [integer]
tags:
- [tag-one]
- [tag-two]
keywords:
- [search phrase]
last_updated: "[YYYY-MM-DD]"
---
[Intro paragraph — 1–3 sentences. State what this page covers and what the reader will be able to do after reading it. No heading.]
## Prerequisites
<RequirementCallout title="Before you begin">
- [Requirement one]
- [Requirement two]
</RequirementCallout>
<MinimumVersionCallout version="[vX.Y.Z]">
[Why this minimum version is required.]
</MinimumVersionCallout>
---
## Overview
[1–3 paragraphs of context. Include a diagram only if the architecture is non-trivial.]
<ArchitectureDiagram
src="/docs/images/[section]/[diagram].svg"
alt="[Describe what the diagram shows]"
caption="[Key takeaway from the diagram.]"
/>
---
## [Main procedure heading]
<Steps>
<Step title="[Step one — verb phrase]">
[1–3 sentences explaining what and why.]
```bash
[command]
```
</Step>
<Step title="[Step two]">
[Content. Nest <Tabs> here if there are OS / language variants.]
</Step>
<Step title="[Step three]">
[Content.]
<Callout type="success" title="Verified">
[How to confirm the step worked.]
</Callout>
</Step>
</Steps>
---
## Configuration reference
<ParameterTable
rows={[
{ name: '[param]', type: '[type]', required: true, description: '[What it controls.]' },
{ name: '[param]', type: '[type]', required: false, default: '[default]', description: '[What it controls.]' },
]}
/>
---
## Troubleshooting
<TroubleshootingTable
columns={[
{ key: 'symptom', label: 'Symptom' },
{ key: 'cause', label: 'Likely cause' },
{ key: 'action', label: 'Action' },
]}
rows={[
{ symptom: '[Symptom]', cause: '[Cause]', action: '[Action.]' },
]}
/>
---
## Related pages
<CardGrid cols={2}>
<Card
title="[Related page]"
description="[One sentence on what the reader finds there.]"
href="/docs/[section]/[page]"
/>
<Card
title="[Related page]"
description="[One sentence on what the reader finds there.]"
href="/docs/[section]/[page]"
/>
</CardGrid>Part 7 — GitHub workflow
Branches: docs/feat/topic-name for new pages, docs/fix/topic-name for fixes, docs/update/topic-name for revisions. Always kebab-case.
Commit format:
docs(section): short present-tense summary under 72 chars
Optional body — explain WHY, not WHAT. Link related issues.
Refs: #issue-numberExamples:
docs(dr): add failback workflow page
docs(core): fix broken link to replication engine concepts
docs(getting-started): update quick start for CLI v2.28Workflow steps:
- Branch from
main:git checkout -b docs/feat/my-new-page - Create or edit your MDX file under
src/content/docs/ - Add the page to
src/content/docs/_config.tsso it appears in the sidebar - Run the dev server locally and verify the page renders
- Compress any new images to under 200 KB before committing
- Open a PR against
mainand request review - Address review comments and merge
Part 8 — Pre-publish checklist
Run through this before flipping status to "published".
Frontmatter
-
titleis unique, under 60 chars, includes the primary keyword -
descriptionis under 160 chars and answers what will I find and do here? -
sectionandcategorymatch_config.tsexactly (case-sensitive) -
sidebar_positionis set and does not collide with adjacent pages -
last_updatedis today's date inYYYY-MM-DD - At least three
tagspresent
Structure
- No
#H1 in the body - Heading levels do not skip (H2 → H3 → H4, never H2 → H4)
- Intro paragraph explains what the page covers without a preceding heading
Links and media
- All internal links use absolute
/docs/paths - All external links use
<ExternalLink> - Every image has descriptive
alttext - Every
<YouTubeEmbed>and<VideoEmbed>has atitleprop - New images are under 200 KB and live in
public/docs/images/[section]/
Code
- Every fenced code block has a language tag
- Commands have actually been tested
- Placeholder values (e.g.
YOUR_TOKEN_HERE) are accompanied by a<Callout>explaining them
Components
- Every
<Tabs>has alabelprop - Every
<Step>has atitleprop -
<RequirementCallout>present when the page has prerequisites - Page renders without console errors in the local dev server
Part 9 — Common MDX errors
| Symptom | Cause | Fix |
|---|---|---|
| Component renders as plain text | Tag name misspelled, or a component that is not registered | Cross-check the spelling against the component catalog in Part 5. |
| Build fails: "Could not parse frontmatter" | Invalid YAML — usually a missing quote, a tab, or a colon inside an unquoted string | Wrap string values that contain colons in double quotes. Use spaces, not tabs. |
| Build fails: "Unexpected token" near a JSX tag | Unclosed JSX tag or HTML-style self-close on a component that expects children | Every tag must close explicitly: <Callout>...</Callout>. Self-close only void components. |
| GFM table renders as pipe-separated text | Table is inside a JSX block, or missing blank lines around it | Put a blank line above and below the table. Use <DocsTable> when inside JSX. |
| Page shows two H1 headings | An extra `# Heading` written in the body | Delete the `#` heading. The H1 is auto-generated from the `title` frontmatter field. |
| Internal link goes to 404 | Relative path used, file renamed, or _config.ts entry missing | Use absolute /docs/section/page paths. Confirm the file exists and is registered in _config.ts. |
| External link opens in same tab without icon | Plain Markdown [text](https://...) used instead of <ExternalLink> | Replace with <ExternalLink href="https://...">text</ExternalLink>. |
| Code block has no syntax highlighting | Language tag missing after the opening backticks | Add the language tag: ```bash, ```yaml, ```typescript, etc. |
| <Tabs> renders all tabs stacked | Missing label prop on <Tabs> | Add label="Descriptive group name" to the opening tag. |
| Page does not appear in the sidebar | section/category values do not match _config.ts, or the page is not registered there | Check the exact values in _config.ts and copy them into frontmatter. Add a new entry if needed. |
What's next
Was this page helpful?
