← Blog

Authoring reference

Every markdown/MDX authoring feature this site supports — callouts, directives, magic-move, mermaid, code blocks, and Svelte islands — in one living page.

|2 min read|
labsreferencemdxdirectives

This page exercises every authoring feature the site supports. It’s a labs .mdx post, so it can also import and hydrate Svelte islands — but everything except the island imports works identically in Trilium-sourced .md posts, because both go through the same Sätteri directive pipeline. For prose and copy-paste snippets, see docs/AUTHORING.md.

Categories & tags

Posts have two taxonomy dimensions:

  • categories — the primary, hierarchical, browsable dimension. Each entry is a /-joined path; a post can belong to several categories at once:

    categories:
    - "Engineering/Frontend/Angular"
    - "Engineering/Frontend/Architecture"

    Every level is its own page — /blog/category/engineering, /blog/category/engineering/frontend, /blog/category/engineering/frontend/angular — and a parent page lists all descendant posts. The post above appears under both Angular and Architecture.

  • tags — a flat, free-form list for search/filter only (no dedicated pages): tags: ["performance", "ssr"].

For Trilium posts there is no categories frontmatter — categories are derived from where the note lives in the Trilium tree. Place the note under a category note (e.g. Engineering › Frontend › Angular) and clone it into Architecture too for multi-membership. The build walks the note’s parents up to the blog root to produce the same /-joined paths.

Callouts

Six themed callout boxes, from :::note:::caution container directives.

:::note — neutral aside.

:::tip — a helpful suggestion.

:::info — informational context.

:::warning — something to be careful about.

:::danger — a destructive or high-risk operation.

:::caution — proceed carefully.

Inline directive: counter

Client state survives interaction: — click it.

Inline directive: note popover

The term stays ordinary wrapping prose; the ⓘ after it opens a native popover: we apply Command Query Responsibility Segregation to the aggregate. Escape or a click outside closes it, and opening a second popover closes the first.

Leaf directives: embeds

A YouTube embed from a leaf directive (::youtube{id=…}):

::sandbox{id=…} and ::gist{id=…} follow the same shape.

Details / disclosure

Hidden content lives inside a :::details{summary="…"} container and renders as a <details-box>.

Tabs

Terminal window
npm install
Terminal window
pnpm install

Code blocks (Expressive Code)

Fenced blocks are styled by Expressive Code — with line numbers, highlights, and collapsible sections driven by the fence meta.

function greet(name: string) {
return `Hello, ${name}!`; // highlighted line
}
export function sum(nums: number[]) {
3 collapsed lines
// collapsed by default
return nums.reduce((a, b) => a + b, 0);
// ...
}

Magic Move — directive syntax

:::magic-move wraps ::::step blocks; each step has a caption and a fenced code block. The wizard animates the transitions between steps.

function formatPrice(amount) {
return "$" + amount;
}
function formatPrice(amount, currency = "USD") {
return currency + " " + amount;
}
function formatPrice(amount, currency = "USD") {
return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
}

Magic Move — raw custom-element tags (MDX only)

The identical wizard authored by hand with <magic-move-wizard> and <div data-step-caption> tags. Both surfaces compile to the same DOM — pick whichever reads better. (Directives also work in Trilium .md; the raw-tag form is convenient in .mdx.)

function greet(name) {
return "Hello, " + name;
}
function greet(name, excited) {
return `Hello, ${name}${excited ? "!" : ""}`;
}

Mermaid diagrams

A fenced ```mermaid block becomes a <mermaid-diagram>:

graph TD; Author-->Preview; Preview-->Publish;

Svelte islands (MDX only)

Trilium Markdown can’t do this — but a labs .mdx post can import and hydrate real Svelte components:

Images

Prefer Astro’s <Image> in labs MDX (CDN + AVIF/WebP + srcset via ImageKit when configured):

import { Image } from "astro:assets";
<Image src="/media/hero.jpg" width={800} height={450} alt="Hero"
transformation={[{ width: 800, quality: 80 }]} />

In Trilium .md (no component imports), use a plain URL — optionally built with the ik() helper (src/lib/ik.ts):

![Hero](https://ik.imagekit.io/your_id/media/hero.jpg?tr=w-800,q-80)