# Markdown Syntax

Every markdown feature, component block, and inline modifier sitemd supports — in one page. Use this as the canonical reference and click through to component-specific docs for deeper coverage.

## How does sitemd parse markdown?

sitemd builds on [marked.js](https://marked.js.org), a fast CommonMark-compliant parser, with a custom preprocessor that handles sitemd's component blocks before markdown rendering. The pipeline runs in this order:

1. Fenced code blocks are extracted and protected so syntax inside them is never preprocessed
2. Component blocks (`button:`, `card:`, `embed:`, `gallery:`, `form:`, `modal:`, etc.) are converted to HTML
3. Layout fences (`center:`, `hidden:`, `gated:`, `mobile:`, `desktop:`) are wrapped in styled `<div>`s
4. Standard markdown is rendered through marked with a custom heading and link renderer
5. Code blocks are restored, and literal `\n` becomes a `<br>`

This means you can mix markdown, HTML, and sitemd components in the same file without escaping anything inside code blocks.

## What standard markdown is supported?

All [CommonMark](https://commonmark.org) features work, plus GitHub-flavored extensions for tables and strikethrough.

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

**bold**, *italic*, ~~strikethrough~~, `inline code`

- Unordered list item
- Another item
  - Nested item

1. Ordered list item
2. Second item

> A blockquote with **inline formatting**.

[A link](/docs/getting-started)
![An image](/media/og-image.png)

---

| Column | Column |
|---|---|
| Cell | Cell |
```

Fenced code blocks support language hints for syntax highlighting:

````markdown
```js
function build() {
  return 'website';
}
```
````

Escape any special character with a backslash: `\*not bold\*` renders literally. Raw HTML tags pass through untouched, so `<details>`, `<span>`, `<kbd>`, and any other element work inline. See [Inline HTML](/docs/inline-html) for details.

## What frontmatter fields are recognized?

Every page starts with YAML frontmatter between `---` delimiters. Lines starting with `#` are treated as comments, which is how the auto-injected syntax reference at the top of every page file works.

```yaml
---
title: My Page
titleSuffix: " | sitemd"
tabTitle: My Page
tabTitleSuffix: " | sitemd"
description: A short summary under 160 characters.
slug: /my-page
sidebarGroupShown: docs
groupMember:
  - docs
updated: 2026-04-08
---
```

| Field | Purpose |
|---|---|
| `title` | Heading shown on the page and in search results |
| `titleSuffix` | Appended to `title` in `<title>` tags |
| `tabTitle` | Optional override for the browser tab title |
| `tabTitleSuffix` | Appended to `tabTitle` |
| `description` | Meta description, under 160 characters |
| `slug` | URL path (`/`, `/about`, `/docs/my-page`) |
| `date` | Publication date (used by blog posts and feeds) |
| `updated` | Last update date — a freshness signal for search engines and AI |
| `layout` | Optional layout variant |
| `ogImage` | Custom Open Graph image URL |
| `groupMember` | Array of group names this page belongs to |
| `sidebarGroupShown` | Which group's sidebar to display on this page |
| `sidebar` | Per-page sidebar override (`self`, `none`, or a custom item list) |

See [Pages & Content](/docs/pages-and-content) for the full authoring reference.

## How do headings and anchors work?

Every heading automatically gets a URL-friendly `id` derived from its text. `## Getting Started` becomes `id="getting-started"`, and duplicate IDs within the same page get a numeric suffix (`-2`, `-3`).

The first `# H1` in a page renders as a true `<h1>`. Every subsequent `# H1` renders as `<h2 class="h1-style">` — visually identical but SEO-correct (one H1 per page).

Add an inline anchor anywhere with `{#id}` on its own line:

```markdown
{#pricing}

## Plans
```

Link to anchors with the standard markdown syntax:

```markdown
[Jump to pricing](#pricing)
[See the themes docs](/docs/themes#custom-colors)
```

See [Headings](/docs/headings) for the full reference.

## How do I add links and buttons?

Inline links use standard markdown. External URLs (`https://...`) automatically open in a new tab. Override that with `+newtab` or `+sametab` appended directly to the URL:

```markdown
[A normal link](/docs/getting-started)
[Force new tab](/docs/headings+newtab)
[Force same tab](https://example.com+sametab)
```

Open a modal from any link by pointing at `#modal:id`:

```markdown
[Open the pricing modal](#modal:pricing)
```

For block-level call-to-action buttons, prefix any line with `button:` followed by a label and target. Consecutive `button:` lines auto-group into a row:

```markdown
button: Get Started: /docs/getting-started
button: View on GitHub: https://github.com/sitemd-cc/sitemd
button: Pricing: /pricing +outline
```

Button modifiers chain freely:

| Modifier | Effect |
|---|---|
| `+outline` | Outline style instead of filled |
| `+big` | Larger padding and font size |
| `+color:#hex` | Custom accent color (`+color:red` or `+color:#3366ff`) |
| `+icon:name` | Lucide icon centered above the label |
| `+icon-left:name` | Icon to the left of the label |
| `+icon-right:name` | Icon to the right of the label |
| `+newtab` / `+sametab` | Force tab behavior |
| Target `none` | No link, pointer cursor preserved |
| Target `silent` | No link, pointer cursor hidden |

The same `button:` prefix works in `settings/header.md`, `settings/footer.md`, and `settings/groups.md`. See [Buttons & Links](/docs/buttons-and-links) for the full reference.

## How do I add images and media?

Standard markdown images work as-is. Append space-separated `+modifier` flags inside the URL parentheses to resize, crop, filter, or expand them:

```markdown
![Logo](/media/sitemd-logo-dark.svg +width:200)
![Hero](/media/og-image.png +crop:1200x600 +corner:curve +expand)
![Profile](/media/profile-pic-cropped.jpeg +width:160 +circle +bw)
```

| Modifier | Effect |
|---|---|
| `+width:N` | Max width in pixels |
| `+height:N` | Forced height in pixels (object-fit cover) |
| `+crop:WxH` | Fixed crop dimensions in pixels |
| `+rotate:1` / `:2` / `:3` | Rotate 90° / 180° / 270° |
| `+corner:none` / `:subtle` / `:curve` | Border radius preset |
| `+circle` | 1:1 aspect ratio with `border-radius:50%` |
| `+square` | 1:1 aspect ratio |
| `+rect` | 3:2 aspect ratio |
| `+bw` | Grayscale filter |
| `+sepia` | Sepia filter |
| `+expand` | Open fullscreen lightbox on click |
| `+noexpand` | Disable lightbox (overrides gallery defaults) |

Self-hosted video files (`.mp4`, `.webm`, `.ogv`, `.mov`, `.m4v`) automatically render as `<video>` instead of `<img>`. Video-only modifiers: `+autoplay` (implies `muted` + `loop` + `playsinline`), `+muted`, `+loop`, `+nocontrols`, `+poster:url`.

Group images side-by-side with `image-row:`, or grid them with `gallery:`:

```markdown
image-row:
  ![Light theme](/media/content/themes/theme-light.png)
  ![Dark theme](/media/content/themes/theme-dark.png)
  ![Paper theme](/media/content/themes/theme-paper.png)

gallery:
  ![Analytics dashboard](/media/content/cards/analytics-dashboard-786d29e8.png)
  ![API gateway](/media/content/cards/api-gateway-2da99fe0.png)
  ![Cloud storage](/media/content/cards/cloud-storage-0ab92466.png)
  ![Bulk sites use case](/media/content/use-cases/bulk-sites.png)
```

`gallery:` accepts flags before the colon: `gallery +noexpand +corner:curve:` disables the lightbox and rounds corners.

Embed third-party content with `embed:` followed by a URL on its own line. sitemd auto-detects YouTube, Vimeo, X/Twitter, Reddit, Instagram, LinkedIn, TikTok, Spotify, and CodePen. Any other URL gets a generic iframe fallback.

```markdown
embed: https://www.youtube.com/watch?v=dQw4w9WgXcQ
embed: https://x.com/sitemdcc/status/1234567890
embed: https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT
```

See [Images](/docs/images) and [Embeds](/docs/embeds) for the full references.

## What rich components are available?

Each component has its own deep-dive doc. The summary table lists the minimum syntax for each:

| Component | Minimal syntax | Deep dive |
|---|---|---|
| Cards | `card: Title` + `card-text:` / `card-image:` / `card-icon:` / `card-link:` | [Cards](/docs/cards) |
| Author cards | `author: Name` + `author-image:` / `author-role:` / `author-bio:` / `author-link:` | [Author Cards](/docs/author-cards) |
| Modals | `modal: id` with indented content (or `tab: Name` for tabbed modals) | [Tooltips & Modals](/docs/tooltips-modals) |
| Tooltips | `[trigger text]{tooltip content}` inline | [Tooltips & Modals](/docs/tooltips-modals) |
| Forms | `form:` followed by indented YAML (`webhook`, `fields`, `pages`) | [Forms](/docs/forms) |
| Dynamic data | `data: source` + `data-display:` (`cards` / `list` / `table` / `detail`) | [Dynamic Data](/docs/dynamic-data) |

A card example to anchor the pattern:

```markdown
card: Zero Config
card-text: Write markdown, get a website.
card-icon: zap
card-link: Get Started: /docs/getting-started

card: Deploy Anywhere
card-text: Cloudflare, GitHub Pages, Vercel, Netlify — or any static host.
card-icon: rocket
card-link: See Deploy: /docs/deploy
```

Consecutive `card:` blocks auto-group into a responsive grid. The same auto-grouping rule applies to `button:` and `author:` blocks.

## How do I align, hide, or gate content?

Layout fences open with `name:` on its own line and close with `/name`. The content between is wrapped in a styled container.

```markdown
center:
# A Centered Heading
button: Centered CTA: /docs/getting-started
/center

right:
A right-aligned paragraph.
/right

hidden:
# SEO Title for Search Engines
/hidden

mobile:
This block only appears on small screens.
/mobile

desktop:
This block only appears on larger screens.
/desktop

gated: subscriber, member
This paragraph only renders for logged-in subscribers or members.
/gated
```

| Fence | Effect | Doc |
|---|---|---|
| `center:` / `right:` / `left:` | Wraps content in `<div class="align-*">` and aligns text, headings, buttons, and images | [Content Alignment](/docs/content-alignment) |
| `hidden:` | Wraps in `<div class="sr-only">` — invisible to sighted visitors but indexed by search engines | [Hidden Content](/docs/hidden-content) |
| `mobile:` / `desktop:` | Wraps in `<div class="device-only device-*">` for device-specific visibility | — |
| `gated: type1, type2` | Wraps in a hidden `<div data-gated>` revealed only to matching user types at runtime | [User Auth](/docs/user-auth) |

## What other inline syntax exists?

A few smaller pieces don't fit anywhere else:

```markdown
{#section-id}
A line that becomes <div id="section-id"></div> for anchor linking.

[hover this]{tooltip definition shown on hover or focus}

A line with a hard\nline break in the middle.
```

| Syntax | Purpose |
|---|---|
| `{#id}` on its own line | Inline anchor for cross-page or in-page linking |
| `[text]{content}` | Inline tooltip — works inside any sentence |
| `\n` (literal backslash + n) | Hard line break, becomes `<br>` |
| Raw HTML tags | Pass through untouched — see [Inline HTML](/docs/inline-html) |

## Quick reference

Everything in one table for fast lookup:

| Category | Syntax | Notes |
|---|---|---|
| Bold | `**text**` | — |
| Italic | `*text*` | — |
| Strikethrough | `~~text~~` | — |
| Inline code | `` `text` `` | — |
| Heading | `# H1` through `###### H6` | First H1 stays, rest become styled H2 |
| Link | `[text](url)` | External opens in new tab by default |
| Link tab override | `[text](url+newtab)` / `+sametab` | — |
| Modal trigger | `[text](#modal:id)` | Opens the named modal |
| Inline anchor | `{#id}` on its own line | — |
| Tooltip | `[text]{content}` | — |
| Hard line break | `\n` (literal) | — |
| Image | `![alt](url)` | — |
| Image modifiers | `![alt](url +width:N +circle +bw +expand)` | See full table above |
| Self-hosted video | `![alt](/media/sitemd-launch-demo-16x9.mp4 +autoplay +loop)` | `.mp4`, `.webm`, `.ogv`, `.mov`, `.m4v` |
| Image row | `image-row:` + indented `![alt](url)` lines | Equal-height row |
| Gallery | `gallery:` + indented `![alt](url)` lines | Grid + lightbox |
| Embed | `embed: URL` | YouTube, Vimeo, X, Reddit, Instagram, LinkedIn, TikTok, Spotify, CodePen, fallback iframe |
| Button | `button: Label: /url` | Auto-groups consecutive lines into a row |
| Button modifiers | `+outline +big +color: +icon: +icon-left: +icon-right:` | — |
| Card | `card: Title` + `card-text:` / `card-image:` / `card-icon:` / `card-link:` | Auto-groups into a grid |
| Author card | `author: Name` + `author-image:` / `author-role:` / `author-bio:` / `author-link:` | Auto-groups |
| Modal | `modal: id` + indented content | `tab: Name` lines create tabs |
| Form | `form:` + indented YAML | `webhook`, `fields`, `pages` |
| Data | `data: source` + `data-display:` + `data-*:` | `cards`, `list`, `table`, `detail` |
| Center / right / left | `center:` ... `/center` | — |
| Hidden | `hidden:` ... `/hidden` | Screen-reader only |
| Mobile / desktop | `mobile:` ... `/mobile` | Device-specific |
| Gated | `gated: type1, type2` ... `/gated` | Auth-required |
| Code block | Triple backticks plus language hint | Enables syntax highlighting |
| Table | `\| col \| col \|` + `\|---\|---\|` | GFM tables |
| Blockquote | `> text` | — |
| List | `- item` or `1. item` | Indent for nesting |
| Horizontal rule | `---` | Also the frontmatter delimiter |
| Raw HTML | `<details>`, `<span>`, etc. | Pass-through |

## Related

- [Markdown](/docs/markdown) — what markdown is and why AI agents prefer it
- [Pages & Content](/docs/pages-and-content) — page authoring, file organization, and frontmatter
- [Headings](/docs/headings) — heading levels, anchor IDs, and the multiple-H1 rule
- [Agent Onboarding](/docs/agent-onboarding) — how the auto-injected syntax reference teaches AI agents this surface area