from multimark import VALID_EXTENSIONS
sorted(VALID_EXTENSIONS)['autolink', 'strikethrough', 'table', 'tagfilter', 'tasklist']
This page explains the five GitHub Flavored Markdown extensions that multimark supports, with examples showing how each one works and how to combine them.
GitHub Flavored Markdown (GFM) extends the CommonMark specification with five additional syntax features. These are the constructs that GitHub recognizes in README files, issues, and pull requests but that are not part of the base CommonMark spec.
Multimark supports all five GFM extensions through the extensions parameter, which accepts a sequence of extension names. Extensions are disabled by default so that the parser remains strictly CommonMark-compliant unless you opt in.
['autolink', 'strikethrough', 'table', 'tagfilter', 'tasklist']
Each extension is independent: you enable only the ones you need.
The table extension adds pipe-table syntax. Columns are separated by | characters, and a header row is separated from body rows by a line of dashes.
from multimark import markdown_to_html
table_md = """\
| Feature | Status |
|------------|--------|
| Tables | ✓ |
| Autolinks | ✓ |
| Tasklists | ✓ |
"""
print(markdown_to_html(table_md, extensions=["table"]))<table>
<thead>
<tr>
<th>Feature</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tables</td>
<td>✓</td>
</tr>
<tr>
<td>Autolinks</td>
<td>✓</td>
</tr>
<tr>
<td>Tasklists</td>
<td>✓</td>
</tr>
</tbody>
</table>
Column alignment is controlled with colons in the separator row: :--- for left, :---: for center, and ---: for right. The renderer emits style="text-align: ..." attributes on the <th> and <td> elements.
aligned = """\
| Left | Center | Right |
|:-----|:------:|------:|
| a | b | c |
"""
print(markdown_to_html(aligned, extensions=["table"]))<table>
<thead>
<tr>
<th align="left">Left</th>
<th align="center">Center</th>
<th align="right">Right</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">a</td>
<td align="center">b</td>
<td align="right">c</td>
</tr>
</tbody>
</table>
The strikethrough extension recognizes ~~text~~ as deleted content, rendering it with <del> tags.
<p>This is <del>no longer</del> relevant.</p>
Strikethrough works inline alongside other formatting. You can combine it with bold, italic, and code spans without issue.
The autolink extension automatically converts bare URLs and email addresses into clickable links without requiring explicit Markdown link syntax.
text = """\
Visit https://github.com for more info.
Send feedback to user@example.com.
"""
print(markdown_to_html(text, extensions=["autolink"]))<p>Visit <a href="https://github.com">https://github.com</a> for more info.</p>
<p>Send feedback to <a href="mailto:user@example.com">user@example.com</a>.</p>
This is the same behavior you see on GitHub: any URL starting with http:// or https:// becomes a link, and email addresses get mailto: links.
The tagfilter extension suppresses a specific set of HTML tags that could be used for XSS attacks, even when unsafe=True is set. The filtered tags are: <textarea>, <style>, <xmp>, <iframe>, <noembed>, <noframes>, <script>, and <plaintext>.
html_input = "Before <script>alert('xss')</script> after"
print(markdown_to_html(html_input, unsafe=True, extensions=["tagfilter"]))<p>Before <script>alert('xss')</script> after</p>
The tags are not removed entirely. Instead, the opening < is replaced with <, rendering them inert while preserving the text content for visibility. This matches GitHub’s behavior for user-generated content.
The tasklist extension renders list items that begin with [ ] or [x] as checkbox items with a special CSS class.
tasks = """\
- [x] Write documentation
- [x] Add tests
- [ ] Publish release
"""
print(markdown_to_html(tasks, extensions=["tasklist"]))<ul>
<li><input type="checkbox" checked="" disabled="" /> Write documentation</li>
<li><input type="checkbox" checked="" disabled="" /> Add tests</li>
<li><input type="checkbox" disabled="" /> Publish release</li>
</ul>
The checkboxes are rendered as <input> elements with type="checkbox" and a disabled attribute (since they are static content, not interactive form elements).
Extensions compose freely. Enable as many as you need by passing multiple names in the extensions list.
doc = """\
## Release Notes
| Change | Status |
|---------------|--------------|
| ~~Old API~~ | Removed |
| New API | Added |
Tasks remaining:
- [x] Update docs at https://example.com/docs
- [ ] Tag release
Contact: releases@example.com
"""
print(markdown_to_html(doc, extensions=["table", "strikethrough", "tasklist", "autolink"]))<h2>Release Notes</h2>
<table>
<thead>
<tr>
<th>Change</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td><del>Old API</del></td>
<td>Removed</td>
</tr>
<tr>
<td>New API</td>
<td>Added</td>
</tr>
</tbody>
</table>
<p>Tasks remaining:</p>
<ul>
<li><input type="checkbox" checked="" disabled="" /> Update docs at <a href="https://example.com/docs">https://example.com/docs</a></li>
<li><input type="checkbox" disabled="" /> Tag release</li>
</ul>
<p>Contact: <a href="mailto:releases@example.com">releases@example.com</a></p>
The order of extension names in the list does not matter. The parser enables all requested extensions before processing the input.
GFM extensions work with all five output formats, not just HTML. Here is the same table rendered as LaTeX.
\begin{table}
\begin{tabular}{ll}
Feature & Status \\
Tables & ✓ \\
Autolinks & ✓ \\
Tasklists & ✓ \\
\end{tabular}
\end{table}
The LaTeX renderer maps table structure to tabular environments. Each renderer translates extension syntax into its native equivalent where possible.