Blazorise CodeEditor component
Add a full-featured source editor to a Blazorise application, starting with two-way binding and growing into custom language tooling.
CodeEditor provides syntax highlighting, diagnostics, completion, formatting, keyboard commands, and strongly typed APIs for common editing scenarios.
The examples below are ordered from basic to advanced. Start with Value and Language; add the other APIs only when the application needs them.
Structure
<CodeEditor>is the main editor component. It binds the document value and exposes options, events, diagnostics, completion, formatting, and programmatic commands.<Feedback>displays validation feedback when the editor is used inside aValidationcomponent.<CodeEditorCustomLanguage>optionally declares a custom language inside the editor.<CodeEditorTokenizer>contains the syntax-highlighting rules for the custom language.<CodeEditorToken>defines a regular-expression rule and the token name applied to matching text.<CodeEditorTokenizerState>groups rules for a named tokenizer state, such as a quoted string or multiline comment.
Installation
NuGet
Install the CodeEditor extension package.Install-Package Blazorise.CodeEditor
Service registration
Register CodeEditor after the main Blazorise services and UI provider. The extension serves and loads its editor assets automatically.
builder.Services
.AddBlazorise()
.AddBootstrap5Providers()
.AddBlazoriseCodeEditor();
Imports
Add the extension namespace to the application's main_Imports.razor.
@using Blazorise.CodeEditor
Examples
Binding
Use@bind-Value for normal two-way binding and choose one of the identifiers from CodeEditorLanguage. Immediate sends user changes to .NET while typing.
78<CodeEditor @bind-Value="" Language="@CodeEditorLanguage.CSharp" Theme="@CodeEditorTheme.VisualStudioDark" Immediate Height="220.Px()" /> <Div Margin="Margin.Is3.FromTop"> <Span TextWeight="TextWeight.SemiBold">Characters:</Span> <Code>@sourceCode.Length</Code> </Div>
@code { private string sourceCode = """ public static string Greet( string name ) { return $"Hello, {name}!"; } """; }
Options
EditorOptions contains editor-specific settings. Ready, Focused, Blurred, and ContentChanged describe the editor lifecycle and user activity. Debouncing keeps frequent server-side value updates under control.
<CodeEditor @ref="" @bind-Value="" Language="@CodeEditorLanguage.JavaScript" EditorOptions="" Immediate Debounce DebounceInterval="250" Ready="" ContentChanged="" Focused="" Blurred="" Height="220.Px()" /> <Div Display="Display.Flex" Flex="Flex.AlignItems.Center" Gap="Gap.Is3" Margin="Margin.Is3.FromTop"> <Button Color="Color.Primary" Clicked="">Focus editor</Button> <Span>@status</Span> </Div>
@code { private CodeEditor editor; private string status = "Waiting for the editor"; private string sourceCode = """ const greeting = name => `Hello, ${name}!`; console.log(greeting("Blazorise")); """; private readonly CodeEditorOptions editorOptions = new() { Minimap = false, WordWrap = true, TabSize = 2, RenderWhitespace = true, ScrollBeyondLastLine = false, FontSize = 14, }; private Task FocusEditor() => editor?.Focus() ?? Task.CompletedTask; private Task OnReady( CodeEditorReadyEventArgs eventArgs ) { status = $"Ready: {eventArgs.ElementId}"; return Task.CompletedTask; } private Task OnContentChanged( string value ) { status = $"Changed: {value.Length} characters"; return Task.CompletedTask; } private Task OnFocused() { status = "Focused"; return Task.CompletedTask; } private Task OnBlurred() { status = "Blurred"; return Task.CompletedTask; } }
Diagnostics
Built-in language support can report syntax diagnostics for supported languages.GetDiagnostics returns a snapshot of the markers currently available, including markers supplied through the Diagnostics parameter.
Edit the JSON or add an application warning.
<CodeEditor @ref="" @bind-Value="" Language="@CodeEditorLanguage.Json" Diagnostics="" Immediate Height="220.Px()" /> <Div Display="Display.Flex" Flex="Flex.Wrap.AlignItems.Center" Gap="Gap.Is2" Margin="Margin.Is3.FromTop"> <Button Color="Color.Primary" Clicked="">Read diagnostics</Button> <Button Color="Color.Warning" Clicked="">Add application warning</Button> <Button Color="Color.Light" Clicked="">Clear application markers</Button> </Div> <Paragraph Margin="Margin.Is3.FromTop"> @status </Paragraph>
@code { private CodeEditor editor; private string status = "Edit the JSON or add an application warning."; private string json = """ { "name": "Blazorise", "debug": true } """; private IReadOnlyList<CodeEditorDiagnostic> applicationDiagnostics = []; private async Task ReadDiagnostics() { IReadOnlyList<CodeEditorDiagnostic> diagnostics = await editor.GetDiagnostics(); CodeEditorDiagnostic firstError = diagnostics.FirstOrDefault( diagnostic => diagnostic.Severity == CodeEditorDiagnosticSeverity.Error ); status = firstError is null ? $"No error markers are currently available. The editor reports {diagnostics.Count} marker(s)." : $"Line {firstError.StartLineNumber}: {firstError.Message}"; } private Task AddApplicationWarning() { applicationDiagnostics = [ new() { Severity = CodeEditorDiagnosticSeverity.Warning, Message = "Disable debug mode before publishing.", Code = "APP001", StartLineNumber = 3, StartColumn = 3, EndLineNumber = 3, EndColumn = 16, }, ]; status = "Application warning added."; return Task.CompletedTask; } private Task ClearApplicationDiagnostics() { applicationDiagnostics = []; status = "Application markers cleared."; return Task.CompletedTask; } }
GetDiagnostics does not start or wait for asynchronous language analysis. Diagnostics describe the markers available at the time of the call; they are not a synchronous compiler or parser. Use a dedicated parser or application validator when validation must complete deterministically.
Validation
PutCodeEditor inside the standard Blazorise validation components. The validator runs only when requested and uses the currently available diagnostics to reject documents that contain error markers.
@using System.Threading <Validations @ref="" Mode="ValidationMode.Manual"> <Validation AsyncValidator=""> <Field> <FieldLabel>JSON configuration</FieldLabel> <FieldBody> <CodeEditor @ref="" @bind-Value="" Language="@CodeEditorLanguage.Json" Immediate Height="220.Px()"> <Feedback> <ValidationError /> </Feedback> </CodeEditor> </FieldBody> </Field> </Validation> <Button Color="Color.Primary" Clicked="">Validate</Button> </Validations>
@code { private CodeEditor editor; private Validations validations; private string json = """ { "name": "Blazorise", "enabled": } """; private Task Validate() => validations.ValidateAll(); private async Task ValidateCode( ValidatorEventArgs eventArgs, CancellationToken cancellationToken ) { cancellationToken.ThrowIfCancellationRequested(); string value = Convert.ToString( eventArgs.Value ); if ( string.IsNullOrWhiteSpace( value ) ) { eventArgs.Status = ValidationStatus.Error; eventArgs.ErrorText = "Enter a JSON document."; return; } IReadOnlyList<CodeEditorDiagnostic> diagnostics = await editor.GetDiagnostics(); cancellationToken.ThrowIfCancellationRequested(); CodeEditorDiagnostic error = diagnostics.FirstOrDefault( diagnostic => diagnostic.Severity == CodeEditorDiagnosticSeverity.Error ); eventArgs.Status = error is null ? ValidationStatus.Success : ValidationStatus.Error; eventArgs.ErrorText = error?.Message; } }
Completion
UseCompletionItems when the same suggestions are valid everywhere. InsertAsSnippet enables numbered placeholders, and CompletionTriggerCharacters can open suggestions after characters such as a dot. Press Ctrl+Space to request suggestions manually.
Type console., or press Ctrl+Space, and select a suggestion. Press Tab to move through snippet placeholders.
<Paragraph> Type <Code>console.</Code>, or press <Code>Ctrl+Space</Code>, and select a suggestion. Press <Code>Tab</Code> to move through snippet placeholders. </Paragraph> <CodeEditor @bind-Value="" Language="@CodeEditorLanguage.JavaScript" CompletionItems="" CompletionTriggerCharacters="" Immediate Height="220.Px()" />
@code { private string sourceCode = """ function greet( name ) { // Type console. here } """; private static readonly IReadOnlyList<string> triggerCharacters = ["."]; private static readonly IReadOnlyList<CodeEditorCompletionItem> completionItems = [ new() { Label = "log", InsertText = "log(${1:value});", Kind = CodeEditorCompletionItemKind.Method, Detail = "Write a message to the console", Documentation = "Inserts console.log with an editable value placeholder.", InsertTextRules = CodeEditorCompletionItemInsertTextRule.InsertAsSnippet, }, new() { Label = "warn", InsertText = "warn(${1:value});", Kind = CodeEditorCompletionItemKind.Method, Detail = "Write a warning to the console", InsertTextRules = CodeEditorCompletionItemInsertTextRule.InsertAsSnippet, }, new() { Label = "error", InsertText = "error(${1:value});", Kind = CodeEditorCompletionItemKind.Method, Detail = "Write an error to the console", InsertTextRules = CodeEditorCompletionItemInsertTextRule.InsertAsSnippet, }, ]; }
Custom language
SupplyLanguages when editing a domain-specific language. Each CodeEditorLanguageDefinition registers an identifier, while its Tokenizer maps regular-expression rules to token names used for syntax highlighting.
<CodeEditor @bind-Value="" Language="" Languages="" Theme="@CodeEditorTheme.VisualStudioDark" Immediate Height="220.Px()" />
@code { private const string workflowLanguageId = "sample-workflow"; private string workflow = """ # A small domain-specific workflow step Build when success run "dotnet build" """; private static readonly IReadOnlyList<CodeEditorLanguageDefinition> workflowLanguages = [ new() { Id = workflowLanguageId, Aliases = ["Workflow"], Extensions = [".workflow"], Tokenizer = new() { IgnoreCase = true, DefaultToken = string.Empty, Tokens = [ new() { Pattern = "\\s+", Token = "white" }, new() { Pattern = "#.*$", Token = "comment" }, new() { Pattern = "\"[^\"\\r\\n]*\"", Token = "string" }, new() { Pattern = "\\b(?:step|when|run|success|failure)\\b", Token = "keyword" }, new() { Pattern = "\\b\\d+\\b", Token = "number" }, new() { Pattern = "[A-Za-z_][A-Za-z0-9_-]*", Token = "identifier" }, ], }, }, ]; }
Custom languages can also be composed declaratively with CodeEditorCustomLanguage, CodeEditorTokenizer, CodeEditorTokenizerState, and CodeEditorToken. Named tokenizer states are useful for strings, comments, and other constructs that need enter-and-exit rules. Language registrations are page-wide, so reuse one definition for each language identifier.
Dynamic completion
UseCodeEditorCompletionProvider.ItemsProvider when suggestions depend on the document or cursor. The callback receives the current value, line, position, word, and trigger character. An item's optional Range tells the editor exactly what text to replace.
Type an opening brace followed by part of a field name, for example {Customer.
<Paragraph> Type an opening brace followed by part of a field name, for example <Code>{Customer</Code>. </Paragraph> <CodeEditor @bind-Value="" Language="@CodeEditorLanguage.PlainText" CompletionProvider="" Immediate Height="220.Px()" />
@code { private string template = "Invoice for "; private static readonly IReadOnlyList<string> fields = [ "Customer.Name", "Customer.Email", "Invoice.Number", "Invoice.Total", ]; private static readonly CodeEditorCompletionProvider completionProvider = new() { Language = CodeEditorLanguage.PlainText, TriggerCharacters = ["{"], ItemsProvider = ProvideFields, }; private static Task<IReadOnlyList<CodeEditorCompletionItem>> ProvideFields( CodeEditorCompletionContext context ) { CodeEditorCompletionRange range = FindFieldRange( context ); if ( range is null ) return Task.FromResult<IReadOnlyList<CodeEditorCompletionItem>>( [] ); IReadOnlyList<CodeEditorCompletionItem> items = fields .Select( field => { string expression = $"{{{field}}}"; return new CodeEditorCompletionItem { Label = expression, InsertText = expression, FilterText = expression, Kind = CodeEditorCompletionItemKind.Field, Detail = "Template field", Range = range, }; } ) .ToArray(); return Task.FromResult( items ); } private static CodeEditorCompletionRange FindFieldRange( CodeEditorCompletionContext context ) { if ( context is null || context.LineNumber < 1 || context.Column < 1 ) return null; string line = context.LineText ?? string.Empty; int cursorIndex = Math.Min( context.Column - 1, line.Length ); string textBeforeCursor = line[..cursorIndex]; int openingIndex = textBeforeCursor.LastIndexOf( '{' ); int closingIndex = textBeforeCursor.LastIndexOf( '}' ); if ( openingIndex <= closingIndex ) return null; int endColumn = cursorIndex < line.Length && line[cursorIndex] == '}' ? context.Column + 1 : context.Column; return new() { StartLineNumber = context.LineNumber, StartColumn = openingIndex + 1, EndLineNumber = context.LineNumber, EndColumn = endColumn, }; } }
Completion positions and ranges use one-based line and column values. Return an empty list when the current context should not offer suggestions. Prefer CompletionItems for fixed data because static suggestions stay entirely in the browser; use ItemsProvider only when .NET needs to inspect the context.
Formatting
AFormattingProvider connects the Format Document action to application code. Call FormatDocument from a button, or let users invoke the standard keyboard command.
@using System.Text.Json <CodeEditor @ref="" @bind-Value="" Language="@CodeEditorLanguage.Json" FormattingProvider="" EditorOptions="" Immediate Height="220.Px()" /> <Div Display="Display.Flex" Flex="Flex.AlignItems.Center" Gap="Gap.Is3" Margin="Margin.Is3.FromTop"> <Button Color="Color.Primary" Clicked="">Format document</Button> <Span>@status</Span> </Div>
@code { private CodeEditor editor; private string status = "Ready"; private string json = """{"name":"Blazorise","features":["completion","diagnostics","formatting"]}"""; private static readonly JsonSerializerOptions serializerOptions = new() { WriteIndented = true, }; private static readonly CodeEditorOptions editorOptions = new() { Minimap = false, FormatOnPaste = true, ScrollBeyondLastLine = false, }; private static readonly CodeEditorDocumentFormattingProvider formattingProvider = new() { Language = CodeEditorLanguage.Json, Formatter = FormatJson, }; private async Task FormatDocument() { bool formatted = await editor.FormatDocument(); status = formatted ? "Formatting provider invoked." : "No formatting provider is available."; } private static Task<string> FormatJson( string value ) { try { using JsonDocument document = JsonDocument.Parse( value ?? string.Empty ); string formattedValue = JsonSerializer.Serialize( document.RootElement, serializerOptions ); return Task.FromResult( formattedValue ); } catch ( JsonException ) { return Task.FromResult( value ); } } }
Keyboard commands
Common commands include Ctrl+Space for completion, Ctrl+F or Cmd+F for find, and Shift+Alt+F or Shift+Option+F for Format Document when a formatting provider is available.
Programmatic control
Keep an @ref when the application needs commands that are not naturally expressed through parameters. Common methods include Focus, GetValue, SetValue, GetSelection, SetSelection, RevealLine, Resize, GetDiagnostics, and FormatDocument.
Update language, theme, diagnostics, completion, formatting, and custom language configuration through component parameters.
API
Parameters
| Parameter | Description | Type | Default |
|---|---|---|---|
AriaDescribedBy |
Specifies the aria-describedby attribute value. RemarksWhen set, this value is rendered as-is and overrides help and validation message ids generated by Field and Validation. |
string | |
AriaInvalid |
Specifies the aria-invalid attribute value. RemarksWhen set, this value is rendered as-is and overrides the validation-derived aria-invalid state. |
string | |
AriaLabelledBy |
Specifies the aria-labelledby attribute value. RemarksWhen set, this value is rendered as-is. Some non-labelable controls can otherwise derive it automatically from a parent FieldLabel or FieldsLabel. |
string | |
AriaRequired |
Specifies the aria-required attribute value. RemarksWhen set, this value overrides the required-field state resolved from the parent Validation. |
bool | false |
Autofocus |
Set's the focus to the component after the rendering is done. |
bool | false |
ChildContent |
Specifies the content to be rendered inside this CodeEditor. |
RenderFragment | null |
CompletionItems |
Gets or sets completion items. |
IReadOnlyList<CodeEditorCompletionItem> | null |
CompletionProvider |
Gets or sets the completion provider. |
CodeEditorCompletionProvider | null |
CompletionTriggerCharacters |
Gets or sets the characters that trigger completion. |
IReadOnlyList<string> | null |
Debounce |
Gets or sets whether user-originated value updates are debounced before being sent to .NET. RemarksWhen supplied, this value overrides the global Blazorise debounce option. |
bool | false |
DebounceInterval |
Gets or sets the debounce interval in milliseconds. RemarksWhen set, this value overrides the global Blazorise debounce interval. |
int? | null |
Diagnostics |
Gets or sets diagnostic markers. |
IReadOnlyList<CodeEditorDiagnostic> | null |
Disabled |
Add the disabled boolean attribute on an input to prevent user interactions and make it appear lighter. |
bool | false |
EditorOptions |
Gets or sets additional editor options. |
CodeEditorOptions | null |
Feedback |
Placeholder for validation messages. |
RenderFragment | null |
FormattingProvider |
Gets or sets the document formatting provider. |
CodeEditorDocumentFormattingProvider | null |
Immediate |
Gets or sets whether user-originated value updates are sent to .NET while typing. RemarksWhen supplied, this value overrides the global Blazorise immediate option. When disabled, the value is sent on blur. |
bool | false |
Language |
Gets or sets the editor language. |
string | |
Languages |
Gets or sets custom language definitions. RemarksCustom language registrations are global to the page. Use one definition per language identifier. |
IReadOnlyList<CodeEditorLanguageDefinition> | null |
ReadOnly |
Add the readonly boolean attribute on an input to prevent modification of the input’s value. |
bool | false |
Size |
Sets the size of the input control. |
Size? | null |
TabIndex |
If defined, indicates that its element can be focused and can participates in sequential keyboard navigation. |
int? | null |
Theme |
Gets or sets the editor theme. RemarksThemes are global. Changing the theme updates every code editor on the page. |
string | |
Value |
Specifies the value inside the input field. |
TValue | null |
ValueExpression |
Specifies an expression that identifies the input value. |
Expression<Func<TValue>> | null |
Events
| Event | Description | Type |
|---|---|---|
Blur |
The blur event fires when an element has lost focus. |
EventCallback<FocusEventArgs> |
Blurred |
Notifies when the editor loses focus. |
EventCallback |
ContentChanged |
Notifies when user-originated editor content changes. RemarksProgrammatic value updates do not raise this event. |
EventCallback<string> |
CustomValidationValue |
Used to provide custom validation value on which the validation will be processed with the Validator handler. RemarksShould be used carefully as it's only meant for some special cases when input is used in a wrapper component, like Autocomplete or SelectList. |
Func<TValue> |
Focused |
Notifies when the editor gains focus. |
EventCallback |
FocusIn |
Notifies when the input box gains focus. |
EventCallback<FocusEventArgs> |
FocusOut |
Notifies when the input box loses focus. |
EventCallback<FocusEventArgs> |
KeyDown |
Notifies when a key is pressed down while the control has focus. |
EventCallback<KeyboardEventArgs> |
KeyPress |
Notifies when a key is pressed while the control has focus. |
EventCallback<KeyboardEventArgs> |
KeyUp |
Notifies when a key is released while the control has focus. |
EventCallback<KeyboardEventArgs> |
OnFocus |
Notifies when the input box gains or loses focus. |
EventCallback<FocusEventArgs> |
Ready |
Notifies when the editor is initialized. |
EventCallback<CodeEditorReadyEventArgs> |
ValueChanged |
Occurs after value has changed. |
EventCallback<TValue> |
Methods
| Method | Description | Return | Parameters |
|---|---|---|---|
FormatDocument |
Formats the current document. | Task<bool> | |
GetDiagnostics |
Gets the diagnostic markers for the current editor model.
RemarksReturns a snapshot of the markers currently available. This method does not start or wait for asynchronous language analysis to complete. | Task<IReadOnlyList<CodeEditorDiagnostic>> | |
GetSelection |
Gets the current editor selection. | Task<CodeEditorSelection> | |
GetValue |
Gets the current editor value. | Task<string> | |
Resize |
Recalculates the editor dimensions to fit its container. | Task | |
RevealLine |
Reveals the specified line. | Task | int lineNumber |
SetSelection |
Sets the current editor selection. | Task | CodeEditorSelection selection |
SetValue |
Sets the current editor value. | Task | string value |
Focus |
Sets the focus on the underline element. | Task | bool scrollToElement |
Revalidate |
Forces the Validation (if any is used) to re-validate with the new custom or internal value. | Task |