Skip to content

Teaching MDX Pages (Docs That Teach)

FieldValue
TypeSkill Resource
Source~/.copilot/skills/technical-writing/references/docs-that-teach/teaching-mdx-guide.md
DescriptionNot specified

Source Content

Teaching MDX Pages (Docs That Teach)

The Docs That Teach standard — how to author a world-class, print-friendly, accessible MDX documentation page that teaches a concept in five minutes using real @dmwd-io/design-system components. Formerly its own skill, now this skill’s teaching-page mode: covered by the same scripts/lint.py pipeline and Diátaxis mode selection as everything else in technical-writing.

Route here for: “write a doc page”, “create an MDX page”, “document this concept”, “write a guide”, “explainer”, “docs for the design system”, “make this readable”, “turn this into a teaching doc”, any task whose output is a .mdx doc in the design system or a consuming app.

Query the Storybook MCP before using any component — never invent one.

The goal is not a wiki page. The goal is a page a developer would choose over a Google search — technically accurate, enjoyable, skimmable, useful on paper, and accessible by default. Documentation that teaches, not just documents.


The one rule everything serves

Every section, table, diagram, code block, and component must help the reader understand faster. If an element does not earn its place by speeding comprehension, cut it. Brevity is not the goal; learning density is.

The reader should leave with: a correct mental model, the reason it matters, practical examples, the common mistakes, and one memorable takeaway. Write for both the skimmer (needs the answer now) and the deep reader (wants the reasoning).


Write at an eighth-grade reading level

Aim for roughly an eighth-grade reading level. That is the sweet spot that makes a doc worth reading — the moment a reader feels they can’t follow it, they leave for a search engine. The audience is still developers, so this is about plain sentences, not a dumbed-down vocabulary.

Keep the real term; cut the needless complexity around it. Say git, not “the place where we store code”. Say CI, pull request, container, env var — your reader knows these, and spelling them out as plain English is slower, not clearer. Plain language means short sentences and common connective words, not removing the words devs already use.

Keep — devs know theseSimplify — needless complexity
git, CI, PR, container, API, env var, cache”utilize” → use · “in order to” → to · “leverage” → use
The precise technical noun for the thing”the place where we store code” → git
One definition on first use, only if the reader might not know it”at this point in time” → now · “in the event that” → if

The rules that get you there:

  • One idea per sentence. Aim under 20 words; split anything over 25. Long sentences are what actually make docs hard — not technical words.
  • Active voice, present tense. “CI runs the checks”, not “the checks are run by CI”.
  • Common word for the glue. Prefer “use”, “help”, “so”, “about”, “before” over “utilize”, “facilitate”, “consequently”, “regarding”, “prior to”.
  • One new concept per paragraph, five sentences or fewer (the technical-writing skill already caps this).
  • Read it aloud. If you run out of breath, the sentence is too long.

Check it (advisory). Run the readability helper for a grade estimate and a list of the longest sentences to split:

Terminal window
python3 ~/.copilot/skills/technical-writing/scripts/readability.py path/to/page.mdx

It targets grade ≈ 8 but never fails the build — necessary technical terms inflate every grade formula, so treat the number as a guide and act on the long-sentence list, which you can fix without dropping a single term.

Earn a highlight in every paragraph

Write so every paragraph leaves at least one line the reader wants to highlight — ideally every sentence. Not a line you wrapped in quotation marks. A line so clean and true that a reader underlines it, screenshots it, or builds a whole LinkedIn post around it. That is the bar on every page, in Markdown, MDX, and plain technical writing alike.

A line earns the highlight three ways:

  • It stands alone. Rip it out of the paragraph and it still lands.
  • It compresses a truth. It says in one breath what most writers take a paragraph to circle.
  • It is earned, not hype. Concrete and a little contrarian beats loud adjectives every time.

The plainest sentence is usually the most quotable, so this pairs with the eighth-grade rule — sharpen the point, do not inflate the words. The technique:

  • Land each paragraph on its sharpest sentence — open or close with it, never bury it in the middle.
  • Use contrast: “X is not Y. It is Z.” The shape itself is memorable.
  • Cut the throat-clearing in front of the good line; the wind-up is rarely the part worth keeping.
  • Vary rhythm — a short, blunt line after two long ones hits hardest.
FlatHighlightable
Reusable workflows help you avoid duplicating CI config.Copy-paste is a loan — you borrow speed today and repay it in every repo you forgot to update.
Good docs are easy to read.The moment a reader feels they can’t follow you, they leave for a search box.
Automating more of the pipeline is usually good.The best workflow isn’t the one with the most automation. It’s the one that makes the right path obvious.

The highlight test — run it on every paragraph: which sentence would a reader underline? If the honest answer is “none”, rewrite one until one earns it. One highlight per paragraph, not a firework in every clause — when every line strains to be profound, none of them land.

Reading-time budget

TargetMaximumWhat it means
5 minutes8 minutes~1,000–1,600 words of prose, plus visuals. If it runs longer, split it into two linked pages — one concept per page.

A page that takes 12 minutes is two pages. Link them; do not merge them.


Frontmatter — always, with the default fields

Every teaching page opens with YAML frontmatter. Use it whenever the format allows (.md and .mdx both do). Six fields are required by default; the rest are recommended when they apply.

FieldTypeWhy
titlestringSpecific and searchable — drives the index and the page H1 intent.
createdISO date YYYY-MM-DDWhen the page was first written.
last_updatedISO date YYYY-MM-DDWhen the content last changed — never before created.
tagsnon-empty listFindability and grouping — [ci, platform].
tldrone-line stringThe skimmer’s “why read this” — one sentence, ≤ 240 chars. The TLDR test: a reader who reads only this must walk away with both the load-bearing claim and the operating consequence. One without the other means rewrite it.
contributorsnon-empty listWho wrote and maintains it — [Jane Doe].

Recommended when they apply, matching the design system’s docs-index.json: status (draft / accepted / superseded), appliesWhen, last_verified.

---
title: Understanding Reusable Workflows
created: 2026-06-24
last_updated: 2026-06-24
status: accepted
tags: [ci, platform]
tldr: Share one CI definition across repos instead of copy-pasting pipeline YAML.
contributors: [David Holmes]
---

Lint it. A page is not done until its frontmatter passes the checker:

Terminal window
python3 ~/.copilot/skills/technical-writing/scripts/lint_docs_that_teach_frontmatter.py path/to/page.mdx
# or a whole tree:
python3 ~/.copilot/skills/technical-writing/scripts/lint_docs_that_teach_frontmatter.py docs/
# need a starting block?
python3 ~/.copilot/skills/technical-writing/scripts/lint_docs_that_teach_frontmatter.py --scaffold

Exit 0 means every required field is present and well-formed; exit 1 lists what is missing or malformed. It accepts contribution / authors as aliases for contributors but nudges you to the canonical name.

Storybook titles come from folders

Storybook derives a docs page’s title and sidebar slot from its file path. Put the page in the right folder and let the folder structure own navigation. Do not add authored title or layout overrides as boilerplate.

Page structure

Use this spine unless the topic clearly needs otherwise. Each heading is a promise the section must keep.

SectionJobLength
TitleSpecific and searchable — answers a real question, never “Overview”1 line
Opening summaryWhat is this, why it matters, when you’d use it2–4 sentences
Mental modelOne metaphor, rule of thumb, or before/after that makes the concept click1–3 sentences
Visual overviewA Mermaid diagram when flow, architecture, ownership, lifecycle, or a decision is involved1 diagram + 1 takeaway sentence
Main explanationLayered: what it is → why it exists → how it works → when to use → when not → what goes wrong4–7 short sections
Key takeawayOne memorable lesson or decision rule — never “In conclusion”1–3 sentences

Full skeleton with real components: page-template.mdx.


Format decision rules

Pick the format by the reader’s job, not by habit. The most common failure is prose where a table or headings belong.

Reader needs to…UseNever
Scan unordered points (benefits, risks, rules, mistakes)Bulleted listA numbered list (implies false sequence)
Follow an ordered procedure (install, migrate, troubleshoot)Numbered listBullets (loses the order)
Compare named options across shared dimensionsComparisonTable or a Markdown tableBold names mashed into one paragraph
Compare two or three named approaches in depthA #### heading per optionA table with multi-sentence cells
Understand flow, architecture, ownership, lifecycle, or a decisionMermaid diagram via InteractiveMermaidA wall of prose describing the flow
See a trend, proportion, or before/after in numbersA chart component (LineChart, BarChart, …)A table the reader has to mentally plot
Pause on a warning, tip, security, or decision noteCallout with the right toneBold text pretending to be a warning
Read code that demonstrates one ideaCodeBlock (static)A giant full-file dump
Run a command and see expected outputCodeBlock language="bash" (static) or PodTerminal (live)A screenshot of a terminal
See a UI state words cannot conveyMedia (figure + caption)A decorative stock image

Two rules that override instinct, inherited from technical-writing:

  • Named-thing comparisons always get headings or a table — never bold names collapsed into a paragraph.
  • Every table cell is filled — use - for any blank.

Every diagram, chart, image, and table must teach. Put a short italic “what to notice” line beneath each one — telling the reader exactly what to pay attention to turns a reference table into a teaching moment. If you cannot write that one sentence, delete the element.

A comparison or failure-pattern table also earns a discriminating column — one that converts each row from vocabulary into a testable condition (“what proves X happened”, “how you’d detect this”). That column is the difference between giving the reader vocabulary and giving them operating discipline.


MDX components — use the real design system, never invent

The design system already ships a component for nearly everything a teaching doc needs. Query the Storybook MCP for the real props before using any component (list-all-documentationget-documentation). Never invent a prop, tone, or variant — it is a hard rule of this codebase.

The mapping from “what you want” to the real @dmwd-io/design-system export, with verified prop shapes and import lines, lives in component-map.md. The short version:

You wantReal componentNote
Callout / note / warning / security boxCallouttone="info|success|warning|danger", optional title, role
Code sampleCodeBlockcode, language, optional filename
Terminal command + outputCodeBlock language="bash" (static) or PodTerminal (live)static prints fine; live needs a print fallback
Decision / comparison matrixComparisonTablecolumns + rows, one highlighted column
Before / afterDiffDisplaychange logs, version diffs
DiagramInteractiveMermaidchart, fileName, height — follow technical-writing’s diagram rules (../mermaid.md)
Figure / screenshotMediarenders <figure>/<figcaption>; alt required, add caption
Quote / callout of a voiceQuoteHighlighttestimonials, expert notes
Steps / checklistStepList / Checklistordered vs check-off
ChartsLineChart, BarChart, AreaChart, …title, labeled axes, units, a “what to notice” line
On-page navDocsAutoToc, TableOfContentsRail, ArticleJumpNavauto-generated from headings
Optional / platform-specific contentTabsnever hide essential info here — print loses it
Secondary detailAccordionnever hide required steps, warnings, or decisions

There is no Quiz / CheckYourUnderstanding component in the catalog. For a check-your-understanding beat, use a Callout role="note" with the question, and an Accordion for the answer — and in print, show both.


The page must teach on paper. Before shipping, confirm:

  • No essential information lives only inside Tabs or Accordion — print collapses both.
  • Every interactive component has a printFallback prop or an adjacent static equivalent.
  • Diagrams read in grayscale (Mermaid does); meaning never depends on color alone.
  • Tables fit the page width; code blocks wrap or stay readable; figures are not tiny.
  • Links have meaningful text (the URL is invisible on paper).

When an interactive demo is the only place a concept lives, add a one-sentence static summary right beside it.


Tell a story, don’t dump notes

Good documentation feels like someone smart walking beside the reader. The spine: start with the problem → show why the old way hurts → introduce the better mental model → demonstrate it → show the result → leave a decision rule. The reader should feel “this is worth my time” by the end of the opening summary.

The opening builds on the hook — it never recovers from it. After a strong first line, the next sentences must add motion — push into the world where the claim is visible — not explain, soften, or hedge. A strong scene can even precede the thesis. The failure mode is a great first line followed by two paragraphs of defensive reasoning.

Use stories to make examples stick

A rule tells the reader what to do. A story shows them what happens when they don’t — and that is the one they remember. Self-help books live on this move: here’s the thing, here’s how it played out, here’s why we do it this way. Use the same three beats whenever a point matters enough to stick.

The pattern is claim → vignette → lesson:

  • Claim. State the principle plainly in one line.
  • Vignette. Drop a short, relatable story — a mistake someone made, a lucky save, what actually happened in practice. Two to four sentences with a named protagonist, the specific friction they hit, and a damning specific consequence line to close on. “A team” is weaker than “Jack’s team”; “things broke” is weaker than “the on-call pager fired at 2am and the bill doubled”. Specificity is what persuades.
  • Lesson. Name the takeaway out loud. Never make the reader guess what the story was for.

Reuse the character. Once you name a protagonist, the reader tracks them — so call them back. Tie the later prescription to the same person you introduced in the diagnosis (“this is the rule that would have saved Jack’s team”). The callback weaves the doc together so it reads as one woven argument, not a stack of separate sections. Mark any composite as composite — “names changed, the pattern is real.”

The rules that keep it honest and sharp:

  • Mistakes teach best. Readers absorb borrowed pain faster than they absorb a rule — someone else’s 2am outage is cheap tuition.
  • Concrete beats abstract. “A team set retries to infinite and DDoSed their own database by lunch” lands; “misconfiguration can cause issues” slides off.
  • Vignette, not chapter. A few sentences for one point. The doc is not a story; it uses stories.
  • Reserve them for what must stick. Not every paragraph needs a tale — use one where a dry example would slide right off.
  • Never fabricate specifics. Real stories must be true. Hypotheticals are fine but must read as hypothetical — “say a team ships…”, “imagine…” — never invented metrics or fake company names dressed up as fact.
Dry ruleClaim → vignette → lesson
Misconfigured retries can cause cascading failures.Retries need a budget. One team set theirs to “infinite” to be safe; a slow dependency hiccuped, every client retried forever, and they DDoSed their own database by lunch. Give every retry a ceiling — “safe” without a limit is just a slower outage.
Centralize CI to avoid drift.Shared CI saves you from silent drift. One team copied their pipeline into twelve repos, patched a security fix in three, and forgot the rest — the gap surfaced in an audit a year later. Define it once so a fix reaches everyone, not just the repos you remember.

How I work

  1. Name the reader and the one thing they should be able to do or decide afterward. If unclear, ask.
  2. Pick the Diátaxis mode with the technical-writing skill — teaching docs are usually explanation or tutorial. One mode per page.
  3. Write the frontmatter firsttitle, created, last_updated, tags, tldr, contributors (use --scaffold to start). Then outline the spine from the page-structure table; each heading is a one-line promise.
  4. Query the Storybook MCP for every component you plan to use; copy real props from get-documentation.
  5. Draft, choosing each format with the decision-rules table. Follow technical-writing’s diagram rules (../mermaid.md) before any diagram.
  6. Add print fallbacks and the “what to notice” line under every visual.
  7. Cut to the 5-minute budget. Split if over 8 minutes.
  8. Run the lintersscripts/lint_docs_that_teach_frontmatter.py, scripts/lint_docs_that_teach.py (Tabs/Accordion print-survival, “what to notice” coverage, component allowlist), and the technical-writing Markdown linter (../../scripts/markdown_lint.py), all to exit 0 — then the review rubric (review-rubric.md).

Self-rubric (the publish gate)

Full rubric: review-rubric.md. The fast version:

  • The main idea is obvious within 30 seconds; a skimmer can follow headings, tables, and diagrams alone.
  • Plain language at ~eighth-grade level — short sentences, common connective words, technical terms kept but not over-explained (readability.py is advisory).
  • Ordered steps are numbered; unordered points are bulleted; comparisons are tables or #### headings.
  • Every diagram, chart, image, and table teaches and has a “what to notice” sentence; comparison/failure tables carry a discriminating (testable-condition) column.
  • Real examples with expected output and at least one common mistake.
  • The points that must stick are carried by a short story (claim → vignette → lesson) with a named protagonist and a damning consequence line — reused on callback where it ties diagnosis to prescription; real stories are true, hypotheticals read as hypothetical.
  • Every component’s props came from the Storybook MCP — none invented.
  • Print-safe: nothing essential hidden in tabs/accordions; interactive elements have fallbacks; grayscale-readable.
  • Accessible: one H1, no skipped levels, alt text, table headers, never color alone, descriptive links, acronyms defined on first use.
  • Every paragraph has at least one highlightable line — a reader would underline it (the highlight test).
  • Ends with a memorable Key Takeaway or Decision Rule — not “In conclusion”.
  • Frontmatter carries title, created, last_updated, tags, tldr, contributors; lint_frontmatter.py exits 0.
  • Reads in ≤ 8 minutes; the technical-writing Markdown linter (../../scripts/markdown_lint.py) exits 0.

References

  • page-template.mdx — the full gold-standard MDX skeleton with real components and frontmatter.
  • component-map.md — every teaching need mapped to the real @dmwd-io/design-system component, with verified props and import lines.
  • review-rubric.md — the six-dimension publish gate (clarity, structure, visual learning, practical use, accessibility, print, enjoyability).
  • scripts/lint_docs_that_teach_frontmatter.py — checks the default frontmatter fields are present and well-formed; --scaffold prints a starter block.
  • scripts/lint_docs_that_teach.py — flags essential content hidden entirely inside Tabs/Accordion (print collapses both), visuals with no “what to notice” line, and JSX components not in an optional --allowlist.
  • scripts/readability.py — advisory eighth-grade-level estimate plus the longest sentences to split; never fails the build.
  • The technical-writing skill — Diátaxis mode selection and house style, plus the mechanical Markdown/MDX rules and linter (../../scripts/markdown_lint.py) and the diagram-type selection and pre/post lint it now owns (../mermaid.md).
  • Stripe Docs · Cloudflare Docs · Diátaxis — the bar.