Skip to content
✨ Publier v1 is live — a polished docs platform built for the open web.
On this page

Markdown syntax

Live cheatsheet of every markdown feature Publier ships out of the box — GFM (tables, task lists, strikethrough, autolinks, footnotes), frontmatter, directive callouts, and the raw-HTML escape hatch.

A live reference for everything the MDX pipeline understands without extra setup. Each section shows the source on the left of the code fence and the rendered result below.

Frontmatter

Every page starts with a YAML block. Astro reads it into the page’s content collection schema; Publier’s nav, sidebar, and SEO use these fields automatically.

---
title: Page title
description: 1–2 sentence summary used in search + meta description
---

Defined by remark-frontmatter (auto-wired by Astro’s MDX integration). Add custom fields freely — they survive into the rendered page’s frontmatter export.

Headings and inline code

Long names in headings and inline code wrap to fit the page on narrow screens. Their text stays unchanged when copied. Fenced code blocks and wide tables keep horizontal scrolling; component content marked not-prose keeps its own styles.

GFM — tables

Pipe-delimited markdown tables, alignment via :--- / ---: / :---:.

Publier keeps wide tables inside a horizontal scroll region so they fit narrow screens. The original table, headers and alignment stay intact. An overflowing table enters the keyboard tab order; focus it and use the browser’s arrow keys to scroll. A table that fits adds no extra tab stop. Horizontal scrolling also works without JavaScript.

| Feature | Status | Notes |
| ------------ | :------: | ---------------------- |
| Tables | shipped | this is one |
| Task lists | shipped | see below |
| Strikethrough| shipped | ~~deprecated stuff~~ |
| Footnotes | shipped | [^1] |
FeatureStatusNotes
Tablesshippedthis is one
Task listsshippedsee below
Strikethroughshippeddeprecated stuff
Footnotesshipped1

GFM — task lists

Tick boxes inside list items.

- [x] Build the parser
- [x] Wire up the renderer
- [ ] Document the syntax
- [ ] Ship to production
  • Build the parser
  • Wire up the renderer
  • Document the syntax
  • Ship to production

GFM — strikethrough

~~tilde-wrapped~~ text renders with a line through it.

The old API was ~~mostly fine~~ unmaintainable.

The old API was mostly fine unmaintainable.

Bare URLs and email addresses get linked automatically — no need to wrap them in <...> or [...](...).

Read more at https://publier.net or mail us at hello@example.com.

Read more at https://publier.net or mail us at hello@example.com.

Container directives

Triple-colon blocks parsed by remark-directive and rewritten into Publier’s <Aside> callouts. Four variants ship — note, tip, caution, danger. See the full reference at Callouts.

:::tip
Use `bunx publier` to try a one-off command without installing the native CLI.
:::

Inline directives (:foo[label]{attr=val}) and leaf directives (::break{align=center}) are also parsed, but Publier ships handlers only for the four container types listed above. Any unhandled directive passes through as a plain HTML node — fine for inert markup, never for user input (see Raw HTML below).

Math (opt-in)

KaTeX, behind docsShell({ math: true }). Wrap inline in $...$ or block in $$...$$. Full demo at Math equations.

Raw HTML — what we DON’T do, and why

Publier intentionally does not wire rehype-raw into the pipeline. Raw HTML in MDX is a footgun: a <script> or an onclick= attribute in user-authored content turns into an XSS sink the moment your docs accept community contributions or render markdown from a CMS.

If you control every author and want raw HTML anyway, the safe pattern is the rehype-raw + rehype-sanitize pair:

astro.config.ts
import { docsShell } from '@publier/shell/integration';
import rehypeRaw from 'rehype-raw';
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
export default defineConfig({
integrations: [docsShell()],
markdown: {
rehypePlugins: [
rehypeRaw,
// sanitize-after-parse — never trust raw HTML before it's been allow-listed
[rehypeSanitize, {
...defaultSchema,
// allow only the tags + attrs you actually need
tagNames: [...(defaultSchema.tagNames ?? []), 'iframe'],
attributes: {
...defaultSchema.attributes,
iframe: ['src', 'title', 'width', 'height', 'allow'],
},
}],
],
},
});

Order matters — rehype-raw first to lift HTML into the AST, rehype-sanitize after to strip anything outside the allow-list. Never run rehype-raw without a sanitizer if any of your content comes from untrusted authors.

For most docs sites, the right answer is “use a Publier component instead.” If you find yourself reaching for <iframe>, <details>, or a custom card layout, see Components — most of it is already there.

Pretty quotes / em-dashes (opt-in)

remark-smartypants converts "foo" → “foo” and -- → —. Not auto-wired (it’s stylistic). Add it via markdown.remarkPlugins — see Plugins.

Code fences

Fenced code goes through astro-expressive-code for syntax highlighting, copy buttons, and titles. Full reference at Code blocks. Quick examples:

```ts title="hello.ts"
const greet = (name: string) => `Hello, ${name}!`;
```
hello.ts
const greet = (name: string) => `Hello, ${name}!`;

What’s auto-wired vs. what isn’t

PluginAuto-wiredWhy
remark-frontmatter✓Required for every page
remark-gfm✓Universal expectation in docs
remark-directive✓Powers :::tip callouts
remark-asides (Publier)✓Renders directive nodes into <Aside>
remark-math + rehype-katexopt-inHeavy peer deps; only enable when needed
astro-mermaidautoDetected when a mermaid fence appears
remark-smartypants—Stylistic; opinionated
rehype-raw—Security risk by default; opt-in only
rehype-sanitize—Pair with rehype-raw if you opt in
rehype-format—Pretty-prints HTML; cosmetic only, no runtime benefit

Anything not listed here is still pluggable — append to markdown.remarkPlugins / markdown.rehypePlugins in astro.config.ts. See Plugins for the integration pattern.

Footnotes

  1. Footnotes work too — remark-gfm lifts them to the bottom of the page. ↩