Skip to content

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#

Tables, with per-column alignment
Markdown (edit me)
Rendered
PackageRoleSize
rendererdisplay24 kB
editorcreatelarger
variablespersonalizesmall

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.

A cell is not a special dialect
Markdown
| Field | Default |
| --- | --- |
| `skipHtml` | **false** |
| `urlTransform` | [defaultUrlTransform](https://example.com) |
Rendered
FieldDefault
skipHtmlfalse
urlTransformdefaultUrlTransform

Task lists#

Task lists
Markdown (edit me)
Rendered
  • 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#

Strikethrough
Markdown
Status: ~~blocked~~ shipped.

A single tilde ~also works~ by default.
Rendered

Status: blocked shipped.

A single tilde also works by default.

A bare URL becomes a link, without needing angle brackets or link syntax.

Literal autolinks
Markdown
Read https://example.com/spec for details.

Mail support@example.com with questions.

Angle brackets still work: <https://example.com>
Rendered

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#

Footnotes, with a generated back-reference
Markdown (edit me)
Rendered

The parser is micromark1, not a set of regular expressions.

Footnotes

  1. Line-oriented matching cannot see block structure, which is where the old corruptions came from. ↩

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#

One document, every GFM feature
Markdown (edit me)
Rendered

Weekly report

Owner: https://example.com/team

TaskOwnerDone
ImporterAdayes
ExporterGraceno
  • Land the parser1
  • Land the writer

Footnotes

  1. 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.

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.

The whole syntax on one page you can edit: Renderer demo.

Last updated on