Monaco Editor in Slidev
This skill covers integrating Monaco Editor (the editor powering VS Code) into your Slidev presentations for live coding, interactive demos, and executable code blocks.
When to Use This Skill
- Live coding demonstrations
- Interactive code editing during presentations
- Running code examples in real-time
- Teaching programming concepts
- Showing auto-completion and type hints
Enabling Monaco Editor
Basic Monaco Block
Add {monaco} to any code block:
const greeting = 'Hello, World!' console.log(greeting)
This creates an editable code block with:
- Syntax highlighting
- Auto-completion
- Type checking (for TypeScript)
- Bracket matching
Monaco with Line Highlighting
const a = 1 const b = 2 // highlighted const c = 3 // highlighted
Monaco Runner
Execute code directly in the presentation:
JavaScript Runner
const numbers = [1, 2, 3, 4, 5] const doubled = numbers.map(n => n * 2) console.log(doubled)
Click "Run" to execute and see output.
TypeScript Runner
interface User { name: string age: number }
const user: User = { name: 'John', age: 30 }
console.log(${user.name} is ${user.age} years old)
Auto-Run on Load
console.log('This runs automatically!')
Show Output Only
// Output shows after one click console.log('Hello!')
Configuration Options
Editor Height
// Taller editor function longFunction() { // ... }
Read-Only Mode
// Cannot be edited const CONSTANT = 'value'
Diff Editor
const original = 'Hello' ~~~ const modified = 'Hello, World!'
Monaco Setup Configuration
setup/monaco.ts
import { defineMonacoSetup } from '@slidev/types'
export default defineMonacoSetup((monaco) => {
// Editor options
return {
editorOptions: {
fontSize: 14,
fontFamily: 'JetBrains Mono, monospace',
minimap: { enabled: false },
lineNumbers: 'on',
wordWrap: 'on',
tabSize: 2,
scrollBeyondLastLine: false,
automaticLayout: true,
},
// Light/dark theme
theme: {
light: 'vs',
dark: 'vs-dark',
},
}
})Custom Themes
import { defineMonacoSetup } from '@slidev/types'
export default defineMonacoSetup((monaco) => {
// Define custom theme
monaco.editor.defineTheme('my-theme', {
base: 'vs-dark',
inherit: true,
rules: [
{ token: 'comment', foreground: '6A9955' },
{ token: 'keyword', foreground: 'C586C0' },
],
colors: {
'editor.background': '#1a1a2e',
},
})
return {
theme: {
dark: 'my-theme',
light: 'vs',
},
}
})Type Definitions
Adding Types for Libraries
// setup/monaco.ts
import { defineMonacoSetup } from '@slidev/types'
export default defineMonacoSetup(async (monaco) => {
// Add React types
const reactTypes = await fetch(
'https://unpkg.com/@types/react/index.d.ts'
).then(r => r.text())
monaco.languages.typescript.typescriptDefaults.addExtraLib(
reactTypes,
'file:///node_modules/@types/react/index.d.ts'
)
})Inline Type Definitions
// Types defined inline interface Todo { id: number text: string completed: boolean }
const todos: Todo[] = [ { id: 1, text: 'Learn Slidev', completed: true }, { id: 2, text: 'Create presentation', completed: false }, ]
Interactive Examples
Counter Demo
// Interactive counter let count = 0
function increment() { count++ console.log(Count: ${count}) }
// Click Run multiple times! increment()
API Simulation
// Simulated API call async function fetchUser(id: number) { // Simulate network delay await new Promise(r => setTimeout(r, 500))
return { id, name: 'John Doe', email: 'john@example.com' } }
const user = await fetchUser(1) console.log(user)
Algorithm Visualization
// Bubble sort with steps function bubbleSort(arr: number[]) { const result = [...arr] const steps: string[] = []
for (let i = 0; i < result.length; i++) { for (let j = 0; j < result.length - i - 1; j++) { if (result[j] > result[j + 1]) { [result[j], result[j + 1]] = [result[j + 1], result[j]] steps.push(Swap: [${result.join(', ')}]) } } }
return { result, steps } }
const { result, steps } = bubbleSort([5, 3, 8, 4, 2]) console.log('Steps:', steps.length) steps.forEach(s => console.log(s)) console.log('Final:', result)
Code Runner Patterns
Show Concept Then Let Edit
# Array Methods
const numbers = [1, 2, 3, 4, 5]
// Try changing the function! const result = numbers .filter(n => n % 2 === 0) .map(n => n * 2)
console.log(result)
Try modifying the code to:
- Filter odd numbers
- Triple instead of doubleInteractive Quiz
# Fix the Bug
// This code has a bug - can you fix it? function reverseString(str: string) { return str.split('').reserve().join('') }
console.log(reverseString('hello')) // Expected: 'olleh'
Live Data Manipulation
const data = [ { name: 'Alice', score: 85 }, { name: 'Bob', score: 92 }, { name: 'Charlie', score: 78 }, ]
// Calculate statistics const average = data.reduce((sum, d) => sum + d.score, 0) / data.length const highest = Math.max(...data.map(d => d.score)) const passing = data.filter(d => d.score >= 80)
console.log(Average: ${average.toFixed(1)}) console.log(Highest: ${highest}) console.log(Passing: ${passing.map(d => d.name).join(', ')})
Combining with Animations
Reveal Then Edit
<v-click>
// Code appears on click, then is editable function greet(name: string) { return Hello, ${name}! }
</v-click>Step-by-Step with Monaco
<v-clicks>
Start with this code:
const x = 1
Then try adding more lines!
</v-clicks>Best Practices
1. Keep Examples Focused
// GOOD: Single concept const sum = [1, 2, 3].reduce((a, b) => a + b, 0) console.log(sum) // 6
2. Provide Starting Point
// Complete the function: function capitalize(str: string): string { // Your code here return str }
console.log(capitalize('hello')) // Should print: 'Hello'
3. Show Expected Output
// Code example const result = [1, 2, 3].map(n => n ** 2) console.log(result) // Expected output: [1, 4, 9]
4. Handle Errors Gracefully
try { const result = riskyOperation() console.log(result) } catch (error) { console.error('Error:', error.message) }
function riskyOperation() { // Might throw an error throw new Error('Oops!') }
Limitations
- No DOM Access: Cannot manipulate the page DOM
- Limited APIs: Only standard JavaScript APIs available
- No Imports: Cannot import external packages
- Console Only: Output is console-based
Output Format
When creating Monaco code blocks:
PURPOSE: [What the code demonstrates]
INTERACTION: [How audience should interact]
CODE:// Clear comments explaining purpose
[Code with good defaults]
// Expected output noted
SUGGESTED EDITS:
- Try changing X to Y
- Modify function to do Z