Code blocks
Fenced code with titles, frames, line/word highlighting, diff markers, and a copy button — powered by astro-expressive-code, auto-wired by Publier.
Fenced code blocks in any .mdx file render through astro-expressive-code, which Publier wires automatically. No imports, no extra config — write Markdown and everything below works.
Plain block
export function hello(name: string) { return `Hello, ${name}!`;}```tsexport function hello(name: string) { return `Hello, ${name}!`;}```Titled block (file-tab chrome)
export function hello(name: string) { return `Hello, ${name}!`;}```ts title="src/lib/greet.ts"export function hello(name: string) { return `Hello, ${name}!`;}```Terminal frame
Shell sessions get a different chrome automatically — bash, sh, zsh, powershell render as a terminal:
pnpm add @publier/shellpublier dev```bashpnpm add @publier/shellpublier dev```Force the terminal chrome on any language with frame="terminal", or drop it entirely with frame="none":
curl https://publier.net | head```bash frame="none"curl https://publier.net | head```Line highlighting
Mark single lines with {n}, ranges with {n-m}, or combine:
function sum(values: number[]) { let total = 0; // highlighted line 2 for (const v of values) total += v; return total;} // highlighted line 5 // highlighted line 6```ts {2,5-6}function sum(values: number[]) { let total = 0; // highlighted line 2 for (const v of values) total += v; return total;} // highlighted line 5 // highlighted line 6```Diff markers (ins / del)
Use semantic labels for additions and deletions:
function sum(values: number[]) { let total: number = 0; let total = 0; for (const v of values) total += v; return total;}```diff lang="ts" function sum(values: number[]) {- let total: number = 0;+ let total = 0; for (const v of values) total += v; return total; }```Word highlighting
Highlight individual strings inside a block:
export function greet(name: string) { return `Hello from greet(): ${name}!`;}```ts "greet"export function greet(name: string) { return `Hello from greet(): ${name}!`;}```Copy button
Every block gets a copy-to-clipboard button in the top-right corner automatically — hover any code fence above to see it. No opt-in required.
Languages
Expressive Code ships Shiki with ~40 languages pre-loaded. Common ones:
def greet(name: str) -> str: return f"Hello, {name}!"fn greet(name: &str) -> String { format!("Hello, {}!", name)}nav: docs: tabs: - label: Documentation href: /docs{ "name": "my-publier-site", "dependencies": { "@publier/shell": "^1.3.1" }}Behaviour
- Syntax highlighting — Shiki via
astro-expressive-code, with theme colors pulled from your active theme’s--color-*tokens so switching themes (maple, aspen, ruby) doesn’t require a rebuild. - Frame chrome styling is auto-injected by Publier.
- Copy button, highlight colors, scrollbars all respect dark mode.
- Zero JavaScript for rendering — the copy button is the only script.
Related
- Grouped alternatives for the same command across languages → Tabs & CodeGroup.
- Install-command switcher with cross-instance sync → PackageInstall.
- Mermaid diagrams in fenced blocks → Mermaid.
- Math expressions in text and display mode → Math equations guide.