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:
```typescript {monaco}
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
```typescript {monaco}{2,3} const a = 1 const b = 2 // highlighted const c = 3 // highlighted
Monaco Runner
Execute code directly in the presentation:
JavaScript Runner
```javascript {monaco-run}
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
```typescript {monaco-run} 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
```javascript {monaco-run} {autorun:true}
console.log('This runs automatically!')
### Show Output Only
```javascript {monaco-run} {showOutputAt:'+1'} // Output shows after one click console.log('Hello!')
Configuration Options
Editor Height
```typescript {monaco}{height:'300px'}
// Taller editor
function longFunction() {
// ...
}
### Read-Only Mode
```typescript {monaco}{readonly:true} // Cannot be edited const CONSTANT = 'value'
Diff Editor
```typescript {monaco-diff}
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
```typescript {monaco} // 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
```typescript {monaco-run}
// Interactive counter
let count = 0
function increment() {
count++
console.log(`Count: ${count}`)
}
// Click Run multiple times!
increment()
### API Simulation
```typescript {monaco-run} // 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
```typescript {monaco-run}
// 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
```typescript {monaco-run} 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 double
Interactive Quiz
# Fix the Bug
```typescript {monaco-run}
// 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
```typescript {monaco-run} 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>
```typescript {monaco}
// Code appears on click, then is editable
function greet(name: string) {
return `Hello, ${name}!`
}
### Step-by-Step with Monaco
Start with this code:
```typescript {monaco} const x = 1
Then try adding more lines!
</v-clicks>
Best Practices
1. Keep Examples Focused
```typescript {monaco-run}
// GOOD: Single concept
const sum = [1, 2, 3].reduce((a, b) => a + b, 0)
console.log(sum) // 6
### 2. Provide Starting Point
```typescript {monaco-run} // Complete the function: function capitalize(str: string): string { // Your code here return str }
console.log(capitalize('hello')) // Should print: 'Hello'
3. Show Expected Output
```typescript {monaco-run}
// Code example
const result = [1, 2, 3].map(n => n ** 2)
console.log(result)
// Expected output: [1, 4, 9]
### 4. Handle Errors Gracefully
```typescript {monaco-run} 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:
```[language] {monaco-run}
// Clear comments explaining purpose
[Code with good defaults]
// Expected output noted
SUGGESTED EDITS:
-
Try changing X to Y
-
Modify function to do Z