Advanced Code Highlighting with Shiki
Why Shiki?
Shiki is a beautiful syntax highlighter powered by the same engine that powers VS Code. Unlike other highlighters, Shiki uses actual TextMate grammars and themes, which means your code will look exactly like it does in your editor.
Key advantages of Shiki:
- Perfect syntax highlighting - Uses VS Code’s language support
- Rich theme ecosystem - Hundreds of themes available
- Zero runtime - All highlighting happens at build time
- Advanced features - Line highlighting, focus effects, and more
Basic Syntax Highlighting
Out of the box, Shiki provides beautiful syntax highlighting for dozens of languages:
// JavaScript with perfect syntax highlighting
const fetchUserData = async (userId) => {
try {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
return userData;
} catch (error) {
console.error('Failed to fetch user:', error);
throw new Error('User fetch failed');
}
};
# Python with beautiful highlighting
def fibonacci(n: int) -> int:
"""Calculate the nth Fibonacci number."""
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# Example usage
for i in range(10):
print(f"F({i}) = {fibonacci(i)}")
// Rust with full syntax support
use std::collections::HashMap;
fn word_frequency(text: &str) -> HashMap<&str, usize> {
let mut frequency = HashMap::new();
for word in text.split_whitespace() {
*frequency.entry(word).or_insert(0) += 1;
}
frequency
}
Line Highlighting
One of Shiki’s most powerful features is the ability to highlight specific lines. This is perfect for drawing attention to important parts of your code.
Meta Highlighting
You can highlight lines using the meta attribute:
function processData(data) {
// This line is highlighted
const processed = data.map(item => ({
id: item.id,
name: item.name.toUpperCase(),
timestamp: new Date()
}));
return processed;
}
Notation Highlighting
You can also use comment-based notation for line highlighting:
interface User {
id: number;
name: string;
email: string;
createdAt: Date;
}
const createUser = (userData: Omit<User, 'id' | 'createdAt'>): User => {
return {
id: Math.random(),
createdAt: new Date(),
...userData
};
};
Focus Effects
Create focus effects to draw attention to specific parts of your code while blurring the rest:
function authenticateUser(username, password) {
// Validation logic
if (!username || !password) {
throw new Error('Username and password required');
}
// This is the important part
const hashedPassword = bcrypt.hashSync(password, 10);
const user = database.findUser(username, hashedPassword);
if (!user) {
throw new Error('Invalid credentials');
}
return generateToken(user);
}
Different Highlighting Styles
Error and Warning Highlighting
Show problematic code with error and warning styling:
function divide(a, b) {
return a / b;
}
function processUser(user) {
console.log(user.name);
// Should validate user object first
if (!user || !user.name) {
throw new Error('Invalid user object');
}
console.log(user.name);
}
Added/Removed Lines
Perfect for showing diffs and changes:
function UserProfile({ user }) {
return (
<div className="profile">
<h1>{user.name}</h1>
<p>{user.email}</p>
<img src={user.avatar} alt="Avatar" /> {}
<img src={user.avatar} alt={`${user.name}'s avatar`} /> {}
</div>
);
}
Here’s a TypeScript example showing API changes:
// Old API
function fetchUser(id: string): Promise<User> {
return fetch(`/api/users/${id}`).then(r => r.json());
}
// New API with error handling
async function fetchUser(id: string): Promise<User | null> {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) return null;
return await response.json();
} catch {
return null;
}
}
Using the Code Component
For even more control, you can use Astro’s built-in <Code />
component with transformers:
const config = {
theme: 'github-dark',
transformers: [
transformerMetaHighlight(),
transformerNotationHighlight()
]
};
Advanced Configuration
Here’s how to configure Shiki in your Astro project for maximum power:
// astro.config.mjs
import { defineConfig } from 'astro/config';
import { transformerMetaHighlight, transformerNotationHighlight } from '@shikijs/transformers';
export default defineConfig({
markdown: {
shikiConfig: {
theme: 'github-dark',
themes: {
light: 'github-light',
dark: 'github-dark'
},
transformers: [
transformerMetaHighlight(),
transformerNotationHighlight(),
transformerNotationDiff(),
transformerNotationErrorLevel(),
transformerNotationFocus()
]
}
}
});
Multi-Language Examples
Shiki supports virtually every programming language you can think of:
Go
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
SQL
-- Complex query with highlighting
SELECT u.id, u.name, COUNT(p.id) as post_count
FROM users u
LEFT JOIN posts p ON u.id = p.user_id // [!code highlight]
WHERE u.created_at > '2024-01-01'
GROUP BY u.id, u.name
HAVING COUNT(p.id) > 5 // [!code focus]
ORDER BY post_count DESC;
CSS
.code-block {
background: #1a1a1a;
border-radius: 8px;
padding: 1rem;
overflow-x: auto;
}
.highlighted-line {
background-color: rgba(59, 130, 246, 0.1);
border-left: 2px solid #3b82f6;
}
Best Practices
- Use highlighting sparingly - Too much highlighting can be overwhelming
- Combine with good explanations - Highlighted code should be explained in your text
- Choose appropriate themes - Match your site’s design
- Test on different devices - Ensure code blocks are readable on mobile
- Keep code blocks focused - Show only the relevant parts
Conclusion
Shiki transforms code presentation from mundane to magnificent. With features like line highlighting, focus effects, and extensive language support, your technical content will be both beautiful and functional.
The combination of Astro’s static generation and Shiki’s build-time highlighting ensures your site remains fast while providing an exceptional reading experience for technical content.
Pro Tip: Experiment with different themes and highlighting combinations to find what works best for your content and audience!