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's off by default because CommonMark is the smaller spec to commit to.
Two routes#
The native extension. gfm() is a Markdown extension, so through a shared preset it also configures the editor and the variables plugin.
import Markdown, { defineMarkdownPreset, gfm } from '@react-markdown-kit/renderer'
const appMarkdown = defineMarkdownPreset({ extensions: [gfm()] })
<Markdown preset={appMarkdown}>{content}</Markdown>The remark plugin. If you already use remark-gfm, it keeps working.
import Markdown from '@react-markdown-kit/renderer'
import remarkGfm from 'remark-gfm'
<Markdown remarkPlugins={[remarkGfm]}>{content}</Markdown>There are fixture tests to make sure both routes agree. tests/gfm.test.ts runs the same GFM corpus through both and compares the rendered HTML, so the plugin route is just as well supported.
I'd pick the extension if you want one dialect shared across the kit, and the plugin if you're migrating and want to change as little as possible.
GfmMarkdown is shorthand for the extension route and takes every prop Markdown does.
Strikethrough with one tilde#
gfm() has one option.
gfm({ singleTilde: false })The default is true, which matches GitHub, cmark-gfm and remark-gfm. With the default, ~x~ gets struck through. Set it to false if you want to require ~~x~~.
Tables#
| Package | Role | Size |
|---|---|---|
| renderer | display | 24 kB |
| editor | create | larger |
| variables | personalize | small |
The second row sets the alignment. :--- is left, :---: is centre and ---: is right.
A cell is an ordinary Markdown subtree, so emphasis, links and code all work inside it.
| Field | Default | | --- | --- | | `skipHtml` | **false** | | `urlTransform` | [defaultUrlTransform](https://example.com) |
| Field | Default |
|---|---|
skipHtml | false |
urlTransform | defaultUrlTransform |
Task lists#
- Parse with micromark
- Keep mdast as the document
- Ship the migration codemod
- Nested items work too
The checkboxes render disabled since rendered Markdown isn't a form. In the editor they're clickable.
The list gets contains-task-list and each item gets task-list-item, matching what GitHub and remark-gfm output. Those are the only classes the renderer adds without you asking for them.
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, without needing angle brackets or 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
The URL policy still applies to autolinks, so an unsafe scheme gets emptied before it reaches the DOM. See Security.
Footnotes#
Numbering follows document order. The footnote section is always rendered last, regardless of where the definitions appear.
A footnote definition is a block, so it can contain 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 still doesn't run. GFM doesn't change the security policy.
Heading anchors, emoji shortcodes and mentions are features of the GitHub website and aren't part of GFM syntax. You can add them with a remark or rehype plugin.
Related#
You can bundle gfm() with your components and policy in a preset and reuse it in the editor.
The editor understands every GFM construct on this page and writes them back unchanged. See Round-trip preservation.
Read next#
The whole syntax on one page you can edit: Renderer demo.
Last updated on