Expressive Code Feature Showcase
- Date —
- July 20, 2026
- Tags —
- Astro, Markdown, Code
This post demonstrates every way you can use Expressive Code in your Markdown. No plugins required — everything here works with the default astro-expressive-code installation.
Syntax Highlighting
Any fenced code block with a language identifier gets syntax highlighting. Over 100 languages are supported out of the box.
function fibonacci(n) { if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2);}
console.log(fibonacci(10)); // 55interface BlogPost { title: string; summary: string; date: Date; tags: string[]; draft: boolean;}
function isPublished(post: BlogPost): boolean { return !post.draft && post.date <= new Date();}.prose { --tw-prose-body: var(--color-ink-soft); --tw-prose-headings: var(--color-ink); --tw-prose-links: var(--color-signal);}
.prose :where(h2, h3, h4) { font-family: var(--font-display);}<header class="sticky top-0 z-40 border-b backdrop-blur"> <nav aria-label="Primary"> <a href="/work" aria-current="page">Work</a> <a href="/blog">Blog</a> </nav></header>Editor Frames
Add a title attribute to show an editor-style frame with a file tab.
export function formatDate(date: Date, style = 'long') { return new Intl.DateTimeFormat('en', { dateStyle: style, timeZone: 'UTC', }).format(date);}---import BaseLayout from '@/layouts/BaseLayout.astro';---
<BaseLayout title="About"> <h1>About me</h1></BaseLayout>{ "name": "astro-starter-portfolio", "type": "module", "scripts": { "dev": "astro dev", "build": "astro build" }}Terminal Frames
Shell languages (bash, sh, zsh, shell) automatically get a terminal-style frame.
pnpm add astro-expressive-codepnpm astro buildpnpm add -g vercelvercel --prodcd ~/projects/astro-starter-portfoliopnpm run devFile Name Comments
If no title is set, Expressive Code extracts a file name from a comment in the first 4 lines.
const href = Astro.props.href;const variant = Astro.props.variant ?? 'solid';:root { --paper: #f7f6f3; --ink: #15161b;}<html lang="en"> <body> <slot /> </body></html>Frame Type Overrides
Force a specific frame type with the frame attribute.
No frame
Use frame="none" to strip the frame entirely — useful for short inline snippets.
const x = 42;Force code frame
Use frame="code" to get an editor frame even without a title.
echo "no frame at all"Force terminal frame
Use frame="terminal" to get a terminal frame for non-shell languages.
node --versionText Markers
Highlight specific lines using the [lineNumbers] meta syntax.
Single line
const SITE = { name: 'Riadh Chelbi', role: 'System Engineer',};Multiple lines
import { getCollection } from 'astro:content';
const allWork = await getCollection('work');const sorted = allWork.sort((a, b) => b.date - a.date);const featured = sorted.filter((e) => e.data.featured);const rest = sorted.filter((e) => !e.data.featured);const selected = [...featured, ...rest].slice(0, 5);Diff-style markers
Use + for additions and - for removals.
const a = 'hello';const b = 'world';const greeting = `${a} ${b}`;const target = greeting;console.log(target);// console.log('done');ANSI Escape Sequences
Set the language to ansi to render terminal output with color.
[1;4mStyles available:[0m [2m- Dimmed[0m [1m- Bold[0m [3m- Italic[0m [4m- Underline[0m [9m- Strikethrough[0m
[1;4mColors:[0m [31m Red [32m Green [33m Yellow [34m Blue [35m Magenta [36m Cyan [0mMultiple Languages
Mix languages in a single post to show different highlighting styles.
integrations: - name: sitemap - name: astro-expressive-code themes: - github-dark-default - github-light-default[tool.ruff]line-length = 100target-version = "py312"
[tool.ruff.lint]select = ["E", "F", "I"]SELECT posts.title, posts.date, COUNT(comments.id) AS comment_countFROM postsLEFT JOIN comments ON comments.post_id = posts.idWHERE posts.draft = falseGROUP BY posts.idORDER BY posts.date DESCLIMIT 10;Nested Code Blocks
You can show Markdown that contains code fences by using extra backticks.
// This is a regular code blockconst x = 1;const std = @import("std");
fn main() { std.debug.print("Hello, World!");}