Blazor component for Microsoft Monaco Editor which powers Visual Studio Code.
Most of the main Monaco Editor feature set is supported with some less-frequently used features currently missing. Any contributions, comments or suggestions are greatly welcome. Please feel free to contact me at x.com/serdarciplak or via GitHub.
The current BlazorMonaco version :
- Uses
Monaco Editor v0.52.2
- Supports
netstandard2.0
,net5.0
,net6.0
,net7.0
,net8.0
andnet9.0
You can see a working sample WebAssembly app here.
-
Add the NuGet package to your Blazor project.
dotnet add package BlazorMonaco // or Install-Package BlazorMonaco
-
Add the script tags below to the end of your html body tag. Note that they must be placed before the Blazor script tag (
blazor.webassembly.js
,blazor.server.js
orblazor.web.js
).<script src="_content/BlazorMonaco/jsInterop.js"></script> <script src="_content/BlazorMonaco/lib/monaco-editor/min/vs/loader.js"></script> <script src="_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.js"></script>
-
Everything resides in three namespaces. You can add the following using directives to your root
_Imports.razor
file, or any other place you may need them.@using BlazorMonaco @using BlazorMonaco.Editor @using BlazorMonaco.Languages
-
Add a
StandaloneCodeEditor
or aStandaloneDiffEditor
component in your razor file and you'll see the editor rendered with the default options.<StandaloneCodeEditor /> <!-- or --> <StandaloneDiffEditor />
Note: If you have any issues like the editor not being visible or not initializing correctly, please check the troubleshooting section below.
To customize your editor's initial options, set the ConstructionOptions
parameter and provide a method that returns a StandaloneEditorConstructionOptions
.
<StandaloneCodeEditor Id="my-code-editor" ConstructionOptions="EditorConstructionOptions" />
@code {
private StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor)
{
return new StandaloneEditorConstructionOptions
{
AutomaticLayout = true,
Language = "javascript",
Value = "function xyz() {\n" +
" console.log(\"Hello world!\");\n" +
"}"
};
}
}
You can subscribe to editor events (e.g. OnDidKeyUp
or OnDidPaste
) via the editor event parameters.
<StandaloneCodeEditor Id="my-code-editor" OnDidChangeCursorPosition="EditorDidChangeCursorPosition" />
@code {
private void EditorDidChangeCursorPosition(CursorPositionChangedEvent eventArgs)
{
Console.WriteLine("EditorDidChangeCursorPosition");
}
}
StandaloneDiffEditor
provides two properties named OriginalEditor
and ModifiedEditor
for accessing the inner editor instances. You can use them like any other StandaloneCodeEditor
instance.
You can register to inner editors' events using the helper event parameters of the main StandaloneDiffEditor
instance.
<StandaloneDiffEditor @ref="_diffEditor" Id="my-diff-editor" OnKeyUpOriginal="OnKeyUpOriginal" OnKeyUpModified="OnKeyUpModified" />
@code {
private StandaloneDiffEditor _diffEditor;
private void OnKeyUpOriginal(KeyboardEvent keyboardEvent)
{
StandaloneCodeEditor originalEditor = _diffEditor.OriginalEditor;
Console.WriteLine("OnKeyUpOriginal : " + keyboardEvent.Code);
}
private void OnKeyUpModified(KeyboardEvent keyboardEvent)
{
StandaloneCodeEditor modifiedEditor = _diffEditor.ModifiedEditor;
Console.WriteLine("OnKeyUpModified : " + keyboardEvent.Code);
}
}
There are 3 css selectors you can use to customize the css styles for your editors.
- All editor instances are contained in a
div
element that has a css class ofmonaco-editor-container
. - The
Id
value you set for your editor instance is also set as the id of its containerdiv
element. - If you set your editor's
CssClass
property, that value is added to the class attribute of its container div element.
That means, the razor component below;
<StandaloneCodeEditor Id="my-editor-id" CssClass="my-editor-class" />
is rendered with the html below;
<div id="my-editor-id" class="monaco-editor-container my-editor-class">
...
</div>
So, you can use css selectors like below to select any element in an editor and customize its styling.
#my-editor-id { /* applies to a specific editor instance */
height: 100px;
}
.my-editor-class { /* applies to all editor instances with this class */
height: 100px;
}
.monaco-editor-container { /* applies to all editor instances */
height: 100px;
}
Monaco Editor JavaScript library defines some methods in the global scope. As C# does not allow global methods, BlazorMonaco groups those methods in two static classes named BlazorMonaco.Editor.Global
and BlazorMonaco.Language.Global
. If you need to use a Monaco Editor method in the global scope, check where in the JavaScript library that method is, and search for it in the corresponding Global
class.
For example, you can use the SetTheme
method like below.
await BlazorMonaco.Editor.Global.SetTheme(jsRuntime, "my-custom-theme");
If you've made changes to Monaco Editor JS library, and need to use this edited version instead of the unmodified version embedded in BlazorMonaco, you can modify the script tags like below.
<script src="_content/BlazorMonaco/jsInterop.js"></script>
<script>var require = { paths: { vs: 'my-path/monaco-editor/min/vs' } };</script>
<script src="my-path/monaco-editor/min/vs/loader.js"></script>
<script src="my-path/monaco-editor/min/vs/editor/editor.main.js"></script>
-
Q: I have added a
StandaloneCodeEditor
as described above, but it's not loading.A: Most possibly, the editor is actually loading but you cannot see it because it has a height of 0. How a DOM element's height can be set depends on its parent elements and their styling. So, BlazorMonaco cannot internally manage the height of the editor instances. If you don't set an editor's height, it may be invisible as it has a height of
0px
. Please add a CSS style to set your editor's height according to where it's placed.#my-editor-id { height: 100px; }
-
Q: The editor does not initialize correctly in my Blazor web app.
A: To be able to work with the interactive MonacoEditor JS library, BlazorMonaco requires an interactive render mode. If you place the editor instance in a page that uses static server-side rendering (static SSR), the editor instance cannot initialize and work.
You can set an interactive render mode globally at the app level,
<!-- In your App.razor file --> <Routes @rendermode="InteractiveServer" />
only for a specific page,
<!-- In the razor file of your page that contains the editor --> @page "/editor-page" @rendermode InteractiveServer <StandaloneCodeEditor />
or only for a component that wraps the editor instance.
<!-- In the razor file of your interactive wrapper component --> @rendermode InteractiveServer <StandaloneCodeEditor />
-
Q: The editor works OK the first time it's displayed. But it is broken (as if its css style is incorrect), if the user navigates to another page and returns back to the editor's page.
A: Please check that the page that contains the editor instance is not opened with Blazor enhanced navigation. Enhanced navigation undos dynamic changes made to the DOM by MonacoEditor JS library and breaks the editor. You need to disable enhanced navigation for pages that contain an editor.
You can set the
data-enhance-nav
attribute of your links tofalse
,<a href="editor-page" data-enhance-nav="false">Editor Page</a>
set
forceLoad
parameter in yourNavigateTo()
calls to true,Navigation.NavigateTo("editor-page", true);
or use the Blazor docs here to see all methods for disabling enhanced navigation.
As BlazorMonaco is just a bridge between JavaScript and Blazor, you can use Monaco Editor's documentation.
After a major version update (like from v2.x
to v3.x
), you may need to make some changes in your integration. Please see the MIGRATE.md file for details.
You can view the history and the changes in the CHANGELOG.md file.
MIT, see the LICENSE file for details.