Logo

Code Blocks

Aug 28, 2025
5 min read

Code Blocks

Expressive Code is a beautiful solution for code blocks that, under the hood, uses Shiki for syntax highlighting. Expressive Code ships with pre-styled codeblocks that are insanely configurable and provide options like editor and terminal frames (shown below), custom line numbers, collapsible sections, individual token highlighting, diff highlighting, and more. To use these for any provided codeblock, simply add any of the following props after the codeblock’s backticks:

Syntax Highlighting

example.md
console.log('This code is syntax highlighted!')
ansi-example.md
ANSI colors:
- Regular: Red Green Yellow Blue Magenta Cyan
- Bold: Red Green Yellow Blue Magenta Cyan
- Dimmed: Red Green Yellow Blue Magenta Cyan
256 colors (showing colors 160-177):
160 161 162 163 164 165
166 167 168 169 170 171
172 173 174 175 176 177
Full RGB colors:
ForestGreen - RGB(34, 139, 34)
Text formatting: Bold Dimmed Italic Underline

Code editor frames

my-test-file.js
// Using `title="my-test-file.js"`
console.log('Title attribute example')
src/content/index.ts
// Using `// src/content/index.ts`
console.log('File name comment example')

Terminal frames

Terminal window
echo "This terminal frame has no title"
PowerShell Terminal Example
Write-Output "This one has a title!"

Marking full lines & line ranges

// Line 1 - targeted by line number
// Line 2
// Line 3
// Line 4 - targeted by line number
// Line 5
// Line 6
// Line 7 - targeted by range "7-8"
// Line 8 - targeted by range "7-8"

Selecting line marker types

  • mark: default marker type, shown as a gray highlight
  • ins: inserted lines, shown with a green highlight and a green bar on the left
  • del: deleted lines, shown with a red highlight and a red bar on the left
line-markers.js
function demo() {
console.log('this line is marked as deleted')
// This line and the next one are marked as inserted
console.log('this is the second inserted line')
return 'this line uses the neutral default marker type'
}

Adding labels to line markers

example.ts
// <- This codeblock starts at line 100!
// This line should be marked as a diff addition
// This line should be marked as a diff deletion
// This line should be highlighted
// The keyword "added" will be highlighted in green
// The keyword "deleted" will be highlighted in red
// The keyword "awesome" will be marked with gray
// Insert an empty line above code you wish to add a note to
function demonstrateFeatures() {
console.log('Hello world!')
return true
}
function obfuscateString(input) {
return Buffer.from(input)
.toString('base64')
.replace(/[A-Za-z]/g, (c) =>
String.fromCharCode(c.charCodeAt(0) + (Math.random() > 0.5 ? 1 : -1)),
)
}
function deleteAllFiles() {
fs.rmdirSync('/etc', { recursive: true })
fs.rmdirSync('/usr', { recursive: true })
fs.rmdirSync('/home', { recursive: true })
return 'System wiped!'
}
// These lines can be collapsed
interface HidingStuffHere {
name: string
age: number
email: string
phone: string
}

Adding long labels on their own lines

example.ts
// <- This codeblock starts at line 100!
// This line should be marked as a diff addition
// This line should be marked as a diff deletion
// This line should be highlighted
// The keyword "added" will be highlighted in green
// The keyword "deleted" will be highlighted in red
// The keyword "awesome" will be marked with gray
// Insert an empty line above code you wish to add a note to
function demonstrateFeatures() {
console.log('Hello world!')
return true
}
function obfuscateString(input) {
return Buffer.from(input)
.toString('base64')
.replace(/[A-Za-z]/g, (c) =>
String.fromCharCode(c.charCodeAt(0) + (Math.random() > 0.5 ? 1 : -1)),
)
}
function deleteAllFiles() {
fs.rmdirSync('/etc', { recursive: true })
fs.rmdirSync('/usr', { recursive: true })
fs.rmdirSync('/home', { recursive: true })
return 'System wiped!'
}
// These lines can be collapsed
interface HidingStuffHere {
name: string
age: number
3 collapsed lines
email: string
phone: string
}

Using diff-like syntax

this line will be marked as inserted
this line will be marked as deleted
this is a regular line
function thisIsJavaScript() {
// This entire block gets highlighted as JavaScript,
// and we can still add diff markers to it!
console.log('Old code to be removed')
console.log('New and shiny code!')
}

Marking individual text inside lines

// Plaintext search strings
function demo() {
// Mark any given text inside lines
return 'Multiple matches of the given text are supported'
}

Marking individual text inside lines

// Regular expressions
console.log('The words yes and yep will be marked.')
Terminal window
# Regular expressions
echo "Test" > /home/test.txt
// Regular expressions
If you only want to mark certain parts matched by your regular expression, you can use capture groups.
For example, the expression `/ye(s|p)/` will match yes and yep, but only mark the character s or p.
// Regular expressions
To prevent this special treatment of capture groups, you can convert them to non-capturing groups by adding ?: after the opening parenthesis.
This block uses `/ye(?:s|p)/`, which causes the full
matching words "yes" and "yep" to be marked.
// Selecting inline marker types (mark, ins, del)
function demo() {
console.log('These are inserted and deleted marker types')
// The return statement uses the default marker type
return true
}

Configuring word wrap per block

// Example with wrap
function getLongString() {
return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide'
}
// Example with wrap=false
function getLongString() {
return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide'
}

Configuring indentation of wrapped lines

// Example with preserveIndent (enabled by default)
function getLongString() {
return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide'
}
// Example with preserveIndent=false
function getLongString() {
return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide'
}

Collapsible sections

5 collapsed lines
// All this boilerplate setup code will be collapsed
import { someBoilerplateEngine } from '@example/some-boilerplate'
import { evenMoreBoilerplate } from '@example/even-more-boilerplate'
const engine = someBoilerplateEngine(evenMoreBoilerplate())
// This part of the code will be visible by default
engine.doSomething(1, 2, 3, calcFn)
function calcFn() {
// You can have multiple collapsed sections
3 collapsed lines
const a = 1
const b = 2
const c = a + b
// This will remain visible
console.log(`Calculation result: ${a} + ${b} = ${c}`)
return c
}
4 collapsed lines
// All this code until the end of the block will be collapsed again
engine.closeConnection()
engine.freeMemory()
engine.shutdown({ reason: 'End of example boilerplate code' })

Displaying line numbers per block

// This code block will show line numbers
console.log('Greetings from line 2!')
console.log('I am on line 3')
// Line numbers are disabled for this block
console.log('Hello?')
console.log('Sorry, do you know what line I am on?')
// Changing the starting line number
console.log('Greetings from line 5!')
console.log('I am on line 6')