This project is a Svelte-based application that integrates the Monaco Editor and a customizable Textarea for rich text editing. Below are the steps to set up and test the project.
To start a new Svelte project, use the following command:
npx sv create test-sv5-me-twb
Install the required development and runtime dependencies:
Development Dependencies:
pnpm i -D @monaco-editor/loader
Runtime Dependencies:
pnpm i monaco-editor
To use a styled Textarea component, you can install shadcn-svelte
. Alternatively, you can use a regular <textarea>
element.
Below is an example setup that uses a Textarea
and a CodeEditor
component:
<script>
import CodeEditor from '$lib/components/code-editor.svelte';
import { Textarea } from '$lib/components/ui/textarea';
let content = $state('<p>Hello, world!</p>');
</script>
<Textarea bind:value={content} rows={4} />
<CodeEditor bind:value={content} />
Below is the implementation of the CodeEditor
component:
<script lang="ts">
import loader from '@monaco-editor/loader';
import type * as Monaco from 'monaco-editor/esm/vs/editor/editor.api';
import { onDestroy, onMount } from 'svelte';
let editor: Monaco.editor.IStandaloneCodeEditor;
let monaco: typeof Monaco;
let editorContainer: HTMLElement;
// Define props with Svelte 5 syntax
interface Props {
value: string;
language?: string;
theme?: string;
}
let { value = $bindable(), language = 'html', theme = 'vs-dark' }: Props = $props();
onMount(() => {
(async () => {
// Remove the next two lines to load the monaco editor from a CDN
// see https://www.npmjs.com/package/@monaco-editor/loader#config
const monacoEditor = await import('monaco-editor');
loader.config({ monaco: monacoEditor.default });
monaco = await loader.init();
// Your monaco instance is ready, let's display some code!
editor = monaco.editor.create(editorContainer, {
value,
language,
theme,
automaticLayout: true,
overviewRulerLanes: 0,
overviewRulerBorder: false,
wordWrap: 'on'
});
editor.onDidChangeModelContent((e) => {
if (e.isFlush) {
// true if setValue call
//console.log('setValue call');
/* editor.setValue(value); */
} else {
// console.log('user input');
const updatedValue = editor?.getValue() ?? ' ';
value = updatedValue;
}
});
})();
});
$effect(() => {
if (value) {
if (editor) {
// check if the editor is focused
if (editor.hasWidgetFocus()) {
// let the user edit with no interference
} else {
if (editor?.getValue() ?? ' ' !== value) {
editor?.setValue(value);
}
}
}
}
if (value === '') {
editor?.setValue(' ');
}
});
onDestroy(() => {
monaco?.editor.getModels().forEach((model) => model.dispose());
editor?.dispose();
});
</script>
<div class="container" bind:this={editorContainer}></div>
<style>
.container {
width: 100%;
height: 600px;
padding: 0;
border-radius: 50px;
}
</style>
CodeEditor
and Textarea
components to your project.content
) to both components.This project is licensed under MIT License.
Contributions are welcome! Please submit a pull request or open an issue if you encounter any problems.