GitHub Flavored Markdown
import { GfmMarkdown } from '@react-markdown-kit/renderer/gfm'
<GfmMarkdown>{content}</GfmMarkdown>
GFM adds tables, task lists, strikethrough, autolinks and footnotes on top of CommonMark. It is off by default, because CommonMark is the smaller promise.
Two routes
The native extension. gfm() is a Markdown extension, so it also configures the editor and the template engine through a shared preset.
import Markdown, { defineMarkdownPreset, gfm } from '@react-markdown-kit/renderer'
const appMarkdown = defineMarkdownPreset({ extensions: [gfm()] })
<Markdown preset={appMarkdown}>{content}</Markdown>
The remark plugin. The plugin you already use keeps working.
import Markdown from '@react-markdown-kit/renderer'
import remarkGfm from 'remark-gfm'
<Markdown remarkPlugins={[remarkGfm]}>{content}</Markdown>
The two routes are fixture-tested to agree. tests/gfm.test.ts runs the same GFM corpus through both and compares the rendered HTML, so the plugin route is not a second-class path.
Pick the extension when you want one dialect shared across the kit. Pick the plugin when you are migrating and want to change as little as possible.
GfmMarkdown is the shorthand for the extension route, and takes every prop Markdown takes.
Strikethrough with one tilde
gfm() takes one option.
gfm({ singleTilde: false })
The default is true, which is what GitHub, cmark-gfm and remark-gfm all do. With the default, ~x~ is struck through. Set it to false to require ~~x~~.
Tables
| Package | Role | Size |
|---|---|---|
| renderer | display | 24 kB |
| editor | create | larger |
| template | personalize | small |
The second row sets alignment. :--- is left, :---: is centre, ---: is right.
A cell is an ordinary Markdown subtree, so emphasis, links and code work inside one.
| Field | Default | | --- | --- | | `skipHtml` | **true** | | `urlTransform` | [defaultUrlTransform](https://example.com) |
| Field | Default |
|---|---|
skipHtml | true |
urlTransform | defaultUrlTransform |
Task lists
- Parse with micromark
- Keep mdast as the document
- Ship the migration codemod
- Nested items work too
The checkboxes render disabled, because rendered Markdown is not a form. The editor makes them clickable.
The list carries contains-task-list and each item carries task-list-item, matching what GitHub and remark-gfm emit. Those are the only classes the renderer adds without being asked.
Strikethrough
Status: ~~blocked~~ shipped. A single tilde ~also works~ by default.
Status: blocked shipped.
A single tilde also works by default.
Autolinks
A bare URL becomes a link with no angle brackets and no link syntax.
Read https://example.com/spec for details. Mail support@example.com with questions. Angle brackets still work: <https://example.com>
Read https://example.com/spec for details.
Mail support@example.com with questions.
Angle brackets still work: https://example.com
URL policy still applies to an autolink. An unsafe scheme is emptied before it reaches the DOM. See Security.
Footnotes
Numbering is derived from document order. The footnote section is rendered last, whatever order the definitions appear in.
A footnote definition is a block, so it can hold paragraphs, lists and code.
Everything at once
Weekly report
Owner: https://example.com/team
| Task | Owner | Done |
|---|---|---|
| Importer | Ada | yes |
| Exporter | Grace |
- Land the parser1
- Land the writer
Footnotes
-
Shipped on Tuesday. ↩
What GFM does not turn on
Raw HTML stays inert. GFM does not change the security policy, and skipHtml still defaults to true.
Heading anchors, emoji shortcodes and mentions are GitHub website features, not GFM syntax. Add them with a remark or rehype plugin.
Related
Bundle gfm() with your components and policy in a preset, then reuse it in the editor.
The editor understands every GFM construct on this page, and writes them back unchanged. See Round-trip preservation.