# Hub Markdown Guide

*How to write Hub Documents: standard Markdown, plus the small set of JWN/Hub-specific extensions layered on top of it — clearly separated, so you always know which is which.*

## Two Kinds of Syntax on This Page {#overview}

This guide covers two genuinely different things:

1. **[Standard Markdown](#standard-markdown)** — the same CommonMark/GitHub-Flavored-Markdown syntax you already know from GitHub, Slack, Notion, and most other tools. Hub's renderer implements this faithfully, with a couple of specific behaviors called out under each feature.
2. **[Custom JWN Directives](#jwn-directives)** — syntax that only exists in Hub. Currently that's exactly one directive: [`:::pagebreak`](#pagebreak).

Every example under Custom JWN Directives is labeled as such. Nothing in the Standard Markdown section is a Hub invention — if it's not in the directives section, it's ordinary Markdown that will work anywhere.

## Standard Markdown {#standard-markdown}

Hub renders document content with [marked](https://marked.js.org/) in GitHub-Flavored-Markdown mode, sanitized with [DOMPurify](https://github.com/cure53/DOMPurify) before display. The same renderer is used everywhere a document's content appears — the Documents editor's live preview, revision history, public shares, and Test Link previews — so what you see in one is what you get in all of them.

### Headings {#headings}

```
# Heading 1
## Heading 2
### Heading 3
```

Renders as three heading levels, each progressively smaller — an actual live example isn't shown on this page since it would inject a competing heading into this guide's own document outline.

**Hub notes:** Every heading gets a stable, GitHub-style `id` (e.g. `## Getting Started` becomes `id="getting-started"`), so you can link to it from elsewhere in the same document with `[jump there](#getting-started)`. Duplicate headings get `-1`, `-2`, etc. appended automatically. Hub only styles heading levels 1–3 distinctly; deeper levels (`####` and beyond) still render correctly but share the same visual weight.

### Paragraphs and Line Breaks {#paragraphs}

```
First paragraph.

Second paragraph, after a blank line.
```

Renders as:

First paragraph.

Second paragraph, after a blank line.

**Hub notes:** This is the one place Hub's renderer deliberately differs from strict CommonMark. Standard CommonMark treats a single line break inside a paragraph as just a space, requiring two trailing spaces (or a backslash) to force a line break. Hub's renderer runs in GFM "breaks" mode instead: **every single line break becomes a visible line break**, matching how most people actually type in a plain-text editor (Slack, Notion, GitHub comments, etc. all behave this way too). If you want two lines to run together as one line, put them on the literal same line in the source, or remove the line break between them.

### Bold and Italic Text {#emphasis}

```
**bold text**, *italic text*, and ***bold italic text***
```

Renders as:

**bold text**, *italic text*, and ***bold italic text***

**Hub notes:** Both `**bold**`/`__bold__` and `*italic*`/`_italic_` forms are supported, same as standard Markdown.

### Links {#links}

```
[Hub](https://hub.justwhatsneeded.com)
```

Renders as:

[Hub](https://hub.justwhatsneeded.com)

**Hub notes:** Links to a heading in the same document use that heading's generated `id` — see [Headings](#headings). Links always render with `target` behavior determined by the surface they're viewed on (editor preview vs. public share); the Markdown syntax itself is unaffected either way.

### Images {#images}

```
![Alt text describing the image](https://example.com/image.png)
```

Renders as an `<img>` tag with the given `src` and `alt` text. This guide doesn't embed a live example image since it would depend on an external URL staying reachable — the syntax above is exactly what to use.

**Hub notes:** Images are not uploaded into Hub itself — the URL must already be reachable on the public internet (or wherever the document's viewers are). There is currently no drag-and-drop image upload in the Documents editor.

### Ordered and Unordered Lists {#lists}

```
- Unordered item
- Another item
  - Nested item

1. First step
2. Second step
```

Renders as:

- Unordered item
- Another item
  - Nested item

1. First step
2. Second step

**Hub notes:** Both `-` and `*` work as unordered bullet markers. Nested lists are indented with two spaces.

### Blockquotes {#blockquotes}

```
> A quoted line.
> A second line in the same quote.
```

Renders as:

> A quoted line.
> A second line in the same quote.

**Hub notes:** Line breaks inside a blockquote follow the same "every line break is visible" behavior described under [Paragraphs and Line Breaks](#paragraphs).

### Inline Code {#inline-code}

```
Use the `resource` and `action` parameters together.
```

Renders as:

Use the `resource` and `action` parameters together.

**Hub notes:** Text inside single backticks is never interpreted as Markdown or as a [JWN directive](#jwn-directives) — see [Escaping Special Characters](#escaping).

### Code Blocks {#code-blocks}

````
```
function greet(name) {
  return "Hello, " + name;
}
```
````

Renders as:

```
function greet(name) {
  return "Hello, " + name;
}
```

**Hub notes:** Content inside a fenced code block is always treated as literal text — including anything that would otherwise look like a [JWN directive](#pagebreak). A `:::pagebreak` line typed inside a fenced code block prints literally and never triggers a page break; see [Page Break](#pagebreak).

### Horizontal Rules {#horizontal-rules}

```
---
```

Renders as:

---

**Hub notes:** `***` and `___` on their own line also produce a horizontal rule, same as standard Markdown.

### Tables {#tables}

```
| Feature | Supported |
|---|---|
| Tables | Yes |
| Task lists | Yes |
```

Renders as:

| Feature | Supported |
|---|---|
| Tables | Yes |
| Task lists | Yes |

**Hub notes:** GitHub-Flavored-Markdown table syntax (pipe-delimited rows, a `---` separator row). Column alignment markers (`:---`, `:---:`, `---:`) are supported the same way GFM defines them.

### Task-List Checkboxes {#task-lists}

```
- [ ] Not done yet
- [x] Done
```

Renders as:

- [ ] Not done yet
- [x] Done

**Hub notes:** Supported. In the Documents editor's own Edit/Preview, checkboxes are interactive — clicking one in Preview flips its state in the underlying Markdown source. Everywhere else the same content is shown read-only (public shares, Test Link previews, revision history), the checkboxes render but are disabled — clicking them does nothing, by design, since there's no logged-in author session to save a change through.

### Escaping Special Characters {#escaping}

```
\*not italic\*, and a literal colon-colon-colon: \:::pagebreak
```

Renders as:

\*not italic\*, and a literal colon-colon-colon: \:::pagebreak

**Hub notes:** A backslash before a Markdown special character (`\*`, `\_`, `` \` ``, `\[`, `\]`, `\#`, `\\`, etc.) forces it to render literally instead of being interpreted. This also works for the [JWN page-break directive](#pagebreak) — escaping its leading colons the same way prints the directive text literally instead of triggering a page break, which is how this exact sentence you're reading now avoided triggering one.

## Custom JWN Directives {#jwn-directives}

**This section is not standard Markdown.** Everything below only works in Hub Documents — copying it into GitHub, Slack, or any other Markdown renderer will just show the literal directive text, since nothing else understands it.

### Page Break — `:::pagebreak` {#pagebreak}

Forces the content immediately after it to begin on a new page when the document is printed or exported to PDF.

Source:

```
Content on the first printed page.

:::pagebreak

Content that always starts on a new printed page.
```

**What it does:**

- **It is a JWN extension, not standard Markdown.** No other Markdown tool recognizes this syntax.
- It forces the content that follows it to begin on a new page in printed or PDF output.
- On screen, it is invisible and adds no visible gap — it does not affect the normal reading layout of the document. (The one exception: in the Documents editor's own live Preview pane, it shows as a small, subtle "Page break" marker so you can see where it lands while writing — that marker itself never prints and never appears anywhere else.)
- It applies everywhere the shared Markdown renderer is used for read-only viewing: public shares, Test Link previews, and any other document view built on the same renderer.
- The directive line itself is never shown in rendered or printed output, under any circumstances — readers only ever see its *effect* (a page break when printing), never the syntax that caused it.

**Recognition rules** (what does and doesn't count as the directive):

- It must be the **only** thing on its own line — `:::pagebreak` with nothing else before or after it on that line (up to 3 leading spaces are tolerated, same as other Markdown block syntax).
- It does **not** trigger inside a fenced code block — see [Code Blocks](#code-blocks).
- It does **not** trigger inside inline code (backticks) — see [Inline Code](#inline-code).
- Anything that isn't an exact match — extra text on the same line, a different number of colons (`::::pagebreak`), or a misspelling — is left alone and simply prints as ordinary text, exactly as typed.
- To show the literal text `:::pagebreak` without triggering a page break, escape it: `\:::pagebreak` — see [Escaping Special Characters](#escaping).

**Do not** expect any other three-colon keyword to do anything — `:::pagebreak` is currently the only implemented directive. This guide does not document speculative directives that don't exist yet.

## Document Metadata {#metadata}

| | |
|---|---|
| **Title** | Hub Markdown Guide |
| **Status** | Canonical |
| **Audience** | Anyone authoring Hub Documents |
| **Guide version** | `1.0` |
| **Last updated** | `2026-08-01` |
| **Canonical URL** | [https://justwhatsneeded.com/markdown-guide.html](https://justwhatsneeded.com/markdown-guide.html) |
| **Related guide** | [Hub API Guide](https://justwhatsneeded.com/api-guide.html) |
| **Purpose** | Reference for standard Markdown support and JWN-specific Markdown extensions in Hub Documents. |

## Keeping This Guide Current {#keeping-current}

This guide has one canonical source — `docs/markdown-guide-source.md` in the `jwn-hub` repository — generated into `markdown-guide.html` by `scripts/generate-markdown-guide.php`. Nobody edits `html/markdown-guide.html` directly; it is build output and gets overwritten the next time the generator runs.

The renderer this guide documents lives in a separate repository: `assets/js/markdown-render.js` in the Hub app repo (`project-hub`), shared verbatim by the Documents editor, revision history, public shares, and Test Link previews. If that renderer's behavior changes — a new directive, a change to an existing one, a change to which standard Markdown features it supports — update this guide (`docs/markdown-guide-source.md`) and regenerate before that work is considered complete.

---

© 2026 Just What's Needed · [Back to Hub overview](https://justwhatsneeded.com/project-hub.html)
