Loading State & Error Boundary
This page demonstrates the advanced features of Monaco Editor Vue3, including loading state management, error handling, and enhanced lifecycle hooks.
Overview
Monaco Editor Vue3 provides comprehensive state management and error handling mechanisms:
- Loading state management: Display editor loading progress and status
- Error boundary: Capture and handle runtime errors in the editor
- Lifecycle hooks: Execute custom logic at different stages of the editor
- Retry mechanism: Allow users to reload when errors occur
- Hook API: Low-level API for custom implementations
1. Basic Usage (with Error Handling & Loading State)
Enhanced CodeEditor Example
vue
<template>
<div>
<h3>Code Editor with Enhanced Features</h3>
<!-- Basic usage -->
<CodeEditor
v-model:value="code"
language="javascript"
theme="vs-dark"
:height="400"
:lifecycle="lifecycleHooks"
@error="handleError"
@ready="handleReady"
@loading="handleLoading"
/>
<!-- Show state -->
<div v-if="editorError" class="error-info">
<h4>Error: {{ editorError.code }}</h4>
<p>{{ editorError.message }}</p>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { CodeEditor, type EditorLifecycleHooks, type EditorError } from 'monaco-editor-vue3';
const code = ref(`function hello() {
console.log('Hello Monaco Editor Vue3!');
return 'Welcome to enhanced editor!';
}`);
const editorError = ref<EditorError | null>(null);
// Lifecycle hooks
const lifecycleHooks: EditorLifecycleHooks = {
beforeCreate: async () => {
console.log('Editor will be created...');
},
onCreated: (editor) => {
console.log('Editor created:', editor);
},
onReady: (editor) => {
console.log('Editor is ready:', editor);
},
onError: (error) => {
console.error('Lifecycle error:', error);
}
};
const handleError = (error: EditorError | null) => {
editorError.value = error;
if (error) {
console.error('Editor error:', error);
}
};
const handleReady = () => {
console.log('Editor is ready for use');
};
const handleLoading = (loadingState: any) => {
console.log('Loading state:', loadingState);
};
</script>
Enhanced DiffEditor Example
vue
<template>
<div>
<h3>Diff Editor with Enhanced Features</h3>
<DiffEditor
v-model:value="modifiedCode"
:original="originalCode"
language="typescript"
theme="vs"
:height="400"
:lifecycle="lifecycleHooks"
loading-text="Loading diff editor..."
:show-progress="true"
@error="handleDiffError"
@ready="handleDiffReady"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { DiffEditor, type EditorLifecycleHooks } from 'monaco-editor-vue3';
const originalCode = ref(`interface User {
id: number;
name: string;
}`);
const modifiedCode = ref(`interface User {
id: number;
name: string;
email: string;
createdAt: Date;
}`);
const lifecycleHooks: EditorLifecycleHooks = {
onReady: (editor) => {
console.log('Diff editor ready');
}
};
const handleDiffError = (error: any) => {
console.error('Diff editor error:', error);
};
const handleDiffReady = () => {
console.log('Diff editor is ready');
};
</script>
2. Advanced Feature Examples
Using the Hook API Directly
vue
<template>
<div>
<div ref="container" style="height: 400px; border: 1px solid #ccc;"></div>
<div v-if="loading.isLoading" class="loading">
Loading: {{ loading.progress }}%
</div>
<div v-if="error" class="error">
Error: {{ error.message }}
<button @click="retry">Retry</button>
</div>
<button v-if="isReady" @click="destroy">Destroy Editor</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useCodeEditor, type EditorLifecycleHooks } from 'monaco-editor-vue3';
const container = ref<HTMLElement>();
const props = {
value: 'console.log("Hello from hook!");',
language: 'javascript',
theme: 'vs-dark',
lifecycle: {
onReady: (editor: any) => {
console.log('Hook: Editor ready', editor);
}
} as EditorLifecycleHooks
};
const emit = (event: string, ...args: any[]) => {
console.log('Event:', event, args);
};
const { loading, error, isReady, retry, destroy } = useCodeEditor(props, emit);
</script>
Standalone Error Boundary Component
vue
<template>
<div>
<MonacoErrorBoundary
:error="sampleError"
@retry="handleRetry"
@report="handleReport"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { MonacoErrorBoundary, createEditorError } from 'monaco-editor-vue3';
const sampleError = ref(createEditorError(
'DEMO_ERROR',
'This is a demonstration error',
'Stack trace would appear here...',
true
));
const handleRetry = () => {
console.log('User clicked retry');
sampleError.value = null;
};
const handleReport = (error: any) => {
console.log('Report error:', error);
};
</script>
3. Custom Loading & Error Components
Monaco Editor Vue3 supports fully custom loading and error state displays.
Using Default Component Configuration
vue
<template>
<CodeEditor
v-model:value="code"
:loading-text="'Loading editor...'"
:show-progress="true"
:show-error-boundary="true"
:retryable="true"
/>
</template>
Custom Loading Component
vue
<template>
<CodeEditor v-model:value="code">
<template #loading="{ loading, loadingText, progress, showProgress }">
<div class="my-custom-loading">
<div class="custom-spinner">🔄</div>
<h3>{{ loadingText }}</h3>
<div v-if="showProgress" class="progress-info">
<span>Progress: {{ progress }}%</span>
<div class="custom-progress-bar">
<div
class="progress-fill"
:style="{ width: `${progress}%` }"
></div>
</div>
</div>
<p>Status: {{ loading.stage }}</p>
</div>
</template>
</CodeEditor>
</template>
<style scoped>
.my-custom-loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.custom-spinner {
font-size: 2rem;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.custom-progress-bar {
width: 200px;
height: 6px;
background: rgba(255,255,255,0.3);
border-radius: 3px;
overflow: hidden;
margin-top: 8px;
}
.progress-fill {
height: 100%;
background: #4CAF50;
transition: width 0.3s ease;
}
</style>
Custom Error Component
vue
<template>
<CodeEditor v-model:value="code">
<template #error="{ error, retry, retryable }">
<div class="my-custom-error">
<div class="error-icon">❌</div>
<h3>Editor Load Failed</h3>
<p class="error-message">{{ error.message }}</p>
<div v-if="error.details" class="error-details">
<details>
<summary>View Details</summary>
<pre>{{ error.details }}</pre>
</details>
</div>
<div class="error-actions">
<button
v-if="retryable"
@click="retry"
class="retry-btn"
>
🔄 Retry
</button>
<button @click="reportError" class="report-btn">
📧 Report Issue
</button>
</div>
<div v-if="error.code" class="error-code">
Error Code: {{ error.code }}
</div>
</div>
</template>
</CodeEditor>
</template>
<script setup>
const reportError = () => {
// Implement error reporting logic
console.log('Reporting error...');
};
</script>
<style scoped>
.my-custom-error {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
background: #fff5f5;
border: 2px dashed #feb2b2;
padding: 2rem;
text-align: center;
}
.error-icon {
font-size: 3rem;
margin-bottom: 1rem;
}
.error-message {
color: #c53030;
margin: 1rem 0;
}
.error-actions {
display: flex;
gap: 1rem;
margin: 1rem 0;
}
.retry-btn, .report-btn {
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 500;
}
.retry-btn {
background: #48bb78;
color: white;
}
.report-btn {
background: #4299e1;
color: white;
}
.error-code {
font-family: monospace;
font-size: 0.875rem;
color: #718096;
margin-top: 1rem;
}
</style>
Fully Disable Default Components
If you want to use only custom components and not show any default ones:
vue
<template>
<CodeEditor
v-model:value="code"
:use-default-loading="false"
:use-default-error-boundary="false"
>
<template #loading="{ loading }">
<MyCustomLoadingComponent :loading-state="loading" />
</template>
<template #error="{ error, retry }">
<MyCustomErrorComponent :error="error" @retry="retry" />
</template>
</CodeEditor>
</template>
Slot Parameter Reference
Loading Slot Parameters
loading
: Complete loading state objectstage
: Current loading stageprogress
: Loading progress (0-100)loadingText
: Loading text
loadingText
: Loading text (from props or default)progress
: Current progressshowProgress
: Whether to show progress
Error Slot Parameters
error
: Error objectmessage
: Error messagedetails
: Error detailscode
: Error coderecoverable
: Whether recoverable
retry
: Retry functionretryable
: Whether retry is allowed
Configuration Options
CodeEditor & DiffEditor Props
loadingText?: string
- Custom loading textshowProgress?: boolean
- Show progress bar (default true)showErrorBoundary?: boolean
- Show error boundary (default true)retryable?: boolean
- Allow retry (default true)useDefaultLoading?: boolean
- Use default loading component (default true)useDefaultErrorBoundary?: boolean
- Use default error component (default true)
Related Events
@loading
- Triggered when loading state changes@error
- Triggered when error state changes@ready
- Triggered when editor is ready
4. Utility Function Examples
Here are some useful utility functions to help you handle various Monaco Editor scenarios:
typescript
import {
createEditorError,
safeAsyncExecution,
isMonacoAvailable,
waitForMonaco,
validateEditorOptions
} from 'monaco-editor-vue3';
// Create a standard error
const error = createEditorError(
'CUSTOM_ERROR',
'Something went wrong',
'Additional details here'
);
// Safely execute async operations
const { success, data, error: execError } = await safeAsyncExecution(
async () => {
// Some async operation that may fail
return await fetch('/api/editor-config');
},
'CONFIG_LOAD_ERROR',
'Failed to load editor configuration'
);
// Check Monaco availability
if (isMonacoAvailable()) {
console.log('Monaco is ready');
} else {
await waitForMonaco(5000); // Wait up to 5 seconds
}
// Validate editor options
const options = { value: 'test', language: 'javascript' };
const validationError = validateEditorOptions(options);
if (validationError) {
console.error('Invalid options:', validationError);
}
5. Best Practices
- Progressive enhancement: Start with default components, then customize as needed
- State management: Use slot parameters to get full state info
- Error handling: Provide user-friendly error messages and recovery options
- Performance: Keep custom components lightweight
- Accessibility: Ensure custom components support keyboard navigation and screen readers