Home · Docs · Editor · Markdown essentials

Markdown essentials

Every Markdown construct sweetdocs supports — what works, what doesn't, and the few extensions we add on top. Verified against the Tiptap + tiptap-markdown configuration.

sweetdocs stores docs as Markdown source, not HTML. Every keystroke serializes to the same Markdown you’d write by hand — paste a doc into another Markdown editor and it works.

This page is the syntax cheat sheet plus the precise list of what we do and don’t support.

Headings

Six levels, plain Markdown:

# H1
## H2
### H3
#### H4
##### H5
###### H6

Or use the slash menu (H1, H2, H3 are the menu items) / the bubble toolbar (H1, H2, H3 buttons appear on selection). H4–H6 are accessible only via raw Markdown — they’re not in either menu.

Inline formatting

StyleSyntaxShortcut
Bold**bold** or __bold__⌘B
Italic*italic* or _italic_⌘I
Strikethrough~~strike~~⌘⇧X
Inline code`code`— (toolbar or backticks)
[link text](https://example.com)

Reference-style ([text][1] plus a separate [1]: url line) does parse on paste, but it gets converted to the inline form when the doc round-trips through our serializer. Don’t rely on the reference syntax surviving.

Plain URLs typed into prose autolink (https://example.com becomes clickable as you type). Links carry rel="noopener noreferrer nofollow" and open in a new tab.

Lists

Bullet lists — -, *, or + all work and round-trip as -:

- First
- Second
  - Nested

Ordered lists:

1. First
2. Second
3. Third

Task lists (- [ ] todo) are not supported — we don’t load the Tiptap task-list extension. The square brackets render as literal text.

Blockquotes

> A blockquote.
> Continues across lines.

Code blocks

Fenced with three backticks, optional language hint after the opening fence:

```javascript
const greet = name => `Hello, ${name}!`
```

The language hint is preserved in the source but there is no syntax highlighting in v1 — code renders as plain monospace on a subtle background. See Code blocks for the details.

Inline code uses single backticks: `code`.

Tables

GFM pipe tables. The header row + separator row are required:

| Column A | Column B | Column C |
|---|---|---|
| Cell | Cell | Cell |

Column alignment (GFM :--- / ---: / :---:):

| Left | Center | Right |
|:---|:---:|---:|
| a | b | c |

Tables in sweetdocs are not resizable by drag (we set resizable: false). Column widths follow content. Insert from the slash menu or paste from a spreadsheet — pasting from Excel / Google Sheets converts the TSV to a real Markdown table.

Horizontal rule

Three or more of any of: -, *, _ on their own line:

---

Images

Standard Markdown:

![alt text](https://image-url.com/cat.png)

For our width + alignment extension, sweetdocs serializes inline HTML so the attributes survive export. See Image layout for the toolbar; the under-the-hood shape is:

<img src="…" alt="…" width="320" class="img-align-center" data-align="center" />

This is standard HTML — other Markdown tools that render embedded HTML show it correctly. The image’s src is a stable URL into our R2-backed storage, so the image keeps loading after export.

See Adding images for paste / drag / upload behaviour.

Smart typography (automatic)

The Typography extension is on. As you type, common ASCII gets replaced by their typographic equivalents:

You typeBecomes
--– (en-dash)
---— (em-dash)
...… (ellipsis)
"hello"”hello” (curly quotes)
'world'’world’ (curly quotes)
(c)©
(r)®
(tm)
1/2, 1/4, 3/4½ ¼ ¾

You can always undo (⌘Z) the substitution if you want the literal characters.

Inline HTML

Inline HTML passes through in both Edit and Preview modes. We need this for the image width/align attributes; we sanitize the Preview render with DOMPurify (so scripts, event handlers, and unsafe attributes are stripped) but keep image attributes, classes, and data-* intact.

Most users never need to write HTML by hand — the toolbars + slash menu cover everything that has a Markdown shape.

sweetdocs extensions on top of Markdown

A small list of things we add that aren’t in plain Markdown:

Hex color swatches

Type any hex literal (#ed4d92, #FFFFFF, #FFFFFFAA) anywhere in body text and a clickable color chip renders next to it in both Edit and Preview. The Markdown source is just the literal — no special syntax.

Comment anchors

When you select text and add a comment, the anchor is stored as an inline <span data-comment-id="…" class="comment-anchor">…</span>. The comment thread itself lives in a separate table and is rendered by the Comments panel.

Image width + alignment

See above — inline HTML attributes, accessible via the image toolbar.

Slash menu

Press / in the editor for block insertion. Not a Markdown extension — a UI shortcut. See The slash menu.

What’s not supported

Things people often look for that aren’t in v1:

ConstructWhy
Task lists (- [ ] / - [x])TaskList Tiptap extension not loaded
Footnotes ([^1])No Footnote extension
Definition lists (Term : definition)No DefinitionList extension
Math / LaTeX ($x^2$, $$ … $$)No Math extension
Callouts / admonitions (:::note … :::)No callout syntax — use a blockquote
Highlight (==text==)No Highlight extension
Subscript / superscript (H~2~O, x^2)No sub / sup extensions
Shortcode emoji (:smile:)Not parsed — paste the actual Unicode character
Reference-style linksParsed on paste, but converted to inline form on save

Any of these will simply render as literal characters in Preview mode.

Render pipeline

The two modes don’t share an engine — they’re kept in sync by sharing the same Markdown source string:

In practice the two produce identical output for every construct on this page. The handful of edge cases where they could diverge (raw <script> tags, exotic CSS) are blocked by DOMPurify.