
Syncfusion Blazor Smart Rich Text Editor
- 229 installs
- 4 repo stars
- Updated July 28, 2026
- syncfusion/blazor-ui-components-skills
Use syncfusion-blazor-smart-rich-text-editor for development tasks
About
syncfusion-blazor-smart-rich-text-editor: A skill for development. This provides functionality for development workflows.
- syncfusion-blazor-smart-rich-text-editor
Syncfusion Blazor Smart Rich Text Editor by the numbers
- 229 all-time installs (skills.sh)
- +13 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #1,729 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/blazor-ui-components-skills --skill syncfusion-blazor-smart-rich-text-editorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 229 |
|---|---|
| repo stars | ★ 4 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/blazor-ui-components-skills ↗ |
What it does
Use syncfusion-blazor-smart-rich-text-editor for development tasks
Files
Syncfusion Blazor Smart Rich Text Editor
A comprehensive skill for implementing and configuring the Syncfusion Blazor Smart Rich Text Editor (SfSmartRichTextEditor) — an AI-powered WYSIWYG editor that extends the full-featured SfRichTextEditor with intelligent content assistance. Supports OpenAI, Azure OpenAI, Ollama, and custom AI backends. Provides a Smart Action dropdown toolbar, an AI query dialog (Alt+Enter), and a fully customizable AI Assistant popup via AssistViewSettings.
When to Use This Skill
Use this skill when the user needs to:
- Install and set up
SfSmartRichTextEditorin a Blazor Server or Web App project - Configure an AI backend: OpenAI, Azure OpenAI, Ollama, or a custom
IChatClient - Register
IChatInferenceService/SyncfusionAIServiceinProgram.cs - Use the Smart Action dropdown toolbar for AI commands (summarize, expand, adjust tone)
- Add
Name = "AI Commands"andName = "AI Query"toToolbarItemModellist to render AI toolbar buttons - Open the AI Query dialog with
Alt+Enterfor free-form AI prompts - Configure
AssistViewSettings:Commands,Suggestions,Prompts,Placeholder,MaxPromptHistory, popup sizing - Customize the AI Assistant popup (
BannerTemplate,HeaderToolbarSettings,PromptToolbarSettings,ResponseToolbarSettings) - Handle AI events:
AIPromptRequested,AIResponseStopped,AIToolbarItemClicked,AIPopupOpening,AIPopupClosing - Use AI Assistant methods:
ShowAIPopupAsync,HideAIPopupAsync,ExecuteAIPromptAsync,UpdateAIResponseAsync,GetAIPromptHistoryAsync,ClearAIPromptHistoryAsync - Style or animate the AI Assistant popup (
.e-rte-aiquery-dialog) - Use all inherited
SfRichTextEditorfeatures: toolbar, images, tables, events, methods, data binding, paste cleanup, import/export, accessibility
Quick Start
1. Install NuGet packages:
dotnet add package Syncfusion.Blazor.SmartRichTextEditor
dotnet add package Syncfusion.Blazor.Themes
dotnet add package Microsoft.Extensions.AI
dotnet add package Microsoft.Extensions.AI.OpenAI2. Register services in `Program.cs`:
using Syncfusion.Blazor;
using Syncfusion.Blazor.AI;
using Microsoft.Extensions.AI;
using OpenAI;
builder.Services.AddSyncfusionBlazor();
string openAIApiKey = "YOUR_API_KEY";
string openAIModel = "gpt-4";
OpenAIClient openAIClient = new OpenAIClient(openAIApiKey);
IChatClient chatClient = openAIClient.GetChatClient(openAIModel).AsIChatClient();
builder.Services.AddChatClient(chatClient);
builder.Services.AddSingleton<IChatInferenceService, SyncfusionAIService>();3. Add to `_Imports.razor`:
@using Syncfusion.Blazor
@using Syncfusion.Blazor.SmartRichTextEditor4. Add CSS/JS in `App.razor` (Server) or `index.html` (WASM):
<link href="_content/Syncfusion.Blazor.Themes/tailwind.css" rel="stylesheet" />
<script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js"></script>5. Add the component:
@rendermode InteractiveServer
<SfSmartRichTextEditor>
<h2>Welcome to Smart Rich Text Editor</h2>
<p>Select text and use the Smart Action toolbar, or press Alt+Enter to open the AI Query dialog.</p>
<AssistViewSettings Placeholder="Ask AI to rewrite or generate content." />
</SfSmartRichTextEditor>Navigation Guide
Getting Started & AI Service Setup
📄 Read: references/getting-started.md
- NuGet installation:
Syncfusion.Blazor.SmartRichTextEditor+Syncfusion.Blazor.Themes - Full setup for Blazor Server App (Visual Studio and VS Code) and Blazor Web App (.NET 8+)
- OpenAI, Azure OpenAI, Ollama, and custom
IChatClientconfiguration inProgram.cs AddInteractiveServerComponents()registration pattern for Web App- CSS theme and JS script references (.NET 6 through .NET 10)
- Adding the component with
AssistViewSettings - Content retrieval methods (
GetTextAsync,GetCharCountAsync) - Common setup issues and fixes
AI Backend Configuration
📄 Read: references/ai-backends.md
- OpenAI: API key, supported models (
gpt-4-turbo,gpt-4,gpt-3.5-turbo),OpenAIClientsetup, environment variables and User Secrets - Azure OpenAI: resource deployment,
AzureOpenAIClient+ApiKeyCredential,appsettings.jsonconfig, Managed Identity (production recommended), HIPAA/SOC 2 compliance, monitoring, cost optimization - Ollama: local model installation (
mistral,llama2),OllamaApiClient+OllamaSharpNuGet, Docker Compose, GPU acceleration, model recommendations - Custom `IChatClient`: implementing
IChatClientfor internal/proprietary AI, registering inProgram.cs, streaming responses, retry logic, error handling, corporate AI API example
AssistViewSettings — Properties
📄 Read: references/assist-view-settings.md
Commands(List<AICommands>): Smart Action dropdown with nested sub-commands and icon CSSPopupMaxHeight/PopupWidth: control popup dimensions (CSS values or pixel numbers)Placeholder: placeholder text in the AI prompt textareaPrompts(List<AssistViewPrompt>): predefined prompt/response templates loaded into the popupSuggestions(List<string>): quick suggestion chips shown in the AI popupMaxPromptHistory: maximum conversation entries retained (default: 20)BannerTemplate: custom branding/headerRenderFragmentfor the AI popupHeaderToolbarSettings/PromptToolbarSettings/ResponseToolbarSettings: toolbar customization withAssistViewToolbarItem
AssistViewSettings — Events
📄 Read: references/ai-events.md
AIPromptRequested(AssistViewPromptRequestedEventArgs): intercept/modify prompt before AI call; setCancel=trueto prevent; modifyResponse,PromptSuggestions,ResponseToolbarItemsAIResponseStopped(ResponseStoppedEventArgs): user clicked "Stop Responding"; providesDataIndexandPromptAIToolbarItemClicked(AssistViewToolbarItemClickedEventArgs): handle custom toolbar button clicks; accessItem,DataIndex,Event; setCancel=trueAIPopupOpening(BeforeOpenEventArgs): cancel popup opening withargs.Cancel = true; accessElementreferenceAIPopupClosing(BeforeCloseEventArgs): cancel popup closing; accessClosedBy,IsInteracted,PreventFocus
AssistViewSettings — Methods
📄 Read: references/ai-methods.md
ShowAIPopupAsync(): open the AI Assistant popup programmaticallyHideAIPopupAsync(): close the AI Assistant popupExecuteAIPromptAsync(string prompt): send a prompt programmatically (as if user typed it)UpdateAIResponseAsync(string response, bool isFinalUpdate): stream or inject AI response; setisFinalUpdate=trueto hide Stop buttonGetAIPromptHistoryAsync(): retrieve all saved prompts/responses asAssistViewPrompt[](chronological, limited toMaxPromptHistory)ClearAIPromptHistoryAsync(): reset all conversation history- Complete example combining all six methods with
@ref
AI Popup Appearance & CSS
📄 Read: references/ai-appearance.md
- CSS selectors for the AI popup:
.e-rte-aiquery-dialog,.e-aiassistview - Customizing popup background, border, box-shadow
- Targeting
.e-view-header,.e-view-content .e-toolbar,.e-footersub-sections for fine-grained control - Full custom popup styling example
Toolbar Configuration
📄 Read: references/toolbar.md
- Enabling or disabling the toolbar with
RichTextEditorToolbarSettings.Enable - Toolbar types: Expand, MultiRow, Scrollable, Popup
- Floating toolbar and offset configuration
- Toolbar position (top or bottom)
- Configuring toolbar items with
ToolbarItemModel - Custom toolbar items (template-based)
Built-in Toolbar Tools Reference
📄 Read: references/built-in-tools.md
- Default toolbar items for
SfSmartRichTextEditor - AI-specific toolbar items —
Name = "AI Commands"(Smart Action dropdown) andName = "AI Query"(Ask AI button); must useNameproperty, NOTToolbarCommandenum - Complete list of all
ToolbarCommandenum values - Text formatting, font & styling, alignment, lists, hyperlinks
- Image/table/link quick toolbar item commands using
SfSmartRichTextEditor - Undo/redo, fullscreen, print, source code, preview tools
- Removing or reordering default toolbar items
Text Formatting
📄 Read: references/text-formatting.md
- Bold, italic, underline, strikethrough, subscript, superscript, inline code
- Text alignment (left, center, right, justify)
- Ordered/unordered lists with custom number and bullet styles
- Heading formats (H1–H6, paragraph, blockquote, code)
- Line height configuration
- Horizontal line, format painter, clear format
- Markdown auto-format (inline and block shortcuts)
Images, Video & Audio
📄 Read: references/images-and-media.md
- Image insertion from local machine or URL
RichTextEditorImageSettings: SaveUrl, Path, AllowedTypes, EnableResize- Base64 vs server-side upload
- Image quick toolbar configuration
- Video and audio insertion and settings
Tables
📄 Read: references/tables.md
- Creating tables with
CreateTabletoolbar item RichTextEditorTableSettings: width, resize, custom styles- Table quick toolbar: add/remove rows & columns, merge cells, properties
- Advanced table manipulation (cell selection, split, custom borders)
Editor Modes
📄 Read: references/editor-modes.md
- HTML editor mode (default WYSIWYG)
- Markdown editor mode (
EditorMode.Markdown) - IFrame vs DIV rendering mode
- Source code view toggling
Inline Mode
📄 Read: references/inline-mode.md
- Enabling inline toolbar (
InlineMode) - Inline toolbar display on text selection
- Use cases: comment editors, in-place content editing
Custom Tools & Exec Commands
📄 Read: references/custom-tools.md
- Adding custom toolbar buttons with
ToolbarItemModeland templates - Executing commands programmatically with
ExecuteCommandAsync - Slash commands (
/trigger menu) configuration - Format painter advanced settings (
RichTextEditorFormatPainterSettings)
Events (RTE)
📄 Read: references/events.md
RichTextEditorEventschild component usage and wiring pattern- Lifecycle events:
Created,Destroyed - Focus/interaction:
Focus,Blur,OnToolbarClick,SelectionChanged - Content events:
ValueChange,BeforePasteCleanup,AfterPasteCleanup - Toolbar lifecycle:
OnActionBegin,OnActionComplete - Dialog events:
OnDialogOpen,DialogOpened,OnDialogClose,DialogClosed - Quick toolbar:
OnQuickToolbarOpen,QuickToolbarOpened,QuickToolbarClosed - Image events:
OnImageSelected,BeforeUploadImage,OnImageUploadSuccess,OnImageUploadFailed,ImageUploadChange,OnImageDrop,ImageDelete - Media events:
FileSelected,FileUploading,FileUploadSuccess,FileUploadFailed,FileUploadChange,OnMediaDrop,MediaDeleted - Resize events:
OnResizeStart,OnResizeStop - Toolbar status:
UpdatedToolbarStatus - Export events:
OnExport,OnExportFailure - Slash menu:
SlashMenuItemSelecting - Complete EventArgs class reference with all properties
Methods (RTE)
📄 Read: references/methods.md
- Focus & selection:
FocusAsync,FocusOutAsync,SaveSelectionAsync,RestoreSelectionAsync,SelectAllAsync,GetSelectionAsync - Content retrieval:
GetTextAsync,GetSelectedHtmlAsync,GetCharCountAsync,GetXhtmlAsync - Command execution: all
ExecuteCommandAsyncoverloads with typed args (image, link, table, video, audio, code block, format painter) - Toolbar control:
EnableToolbarItem,DisableToolbarItem,RemoveToolbarItem - Dialog & UI control:
ShowDialogAsync,CloseDialogAsync,ShowFullScreenAsync,PrintAsync,RefreshUIAsync,ShowSourceCodeAsync - Undo/redo:
ClearUndoRedoAsync - Full
CommandName,ToolbarCommand, andDialogTypeenum references
Properties (RTE)
📄 Read: references/properties.md
- Content & value:
Value,Placeholder,Readonly,Enabled,MaxLength,ShowCharCount - Editor behaviour:
EditorMode,EnterKey,ShiftEnterKey,EnableTabKey,EnableAutoUrl,EnableMarkdownAutoFormat,EnableClipboardCleanup,EnableXhtml,EnableHtmlEncode,EnableResize - Appearance & layout:
Height,Width,CssClass,ShowTooltip,FloatingToolbarOffset - IFrame mode:
RichTextEditorIFrameSettingschild component withEnable,Attributes,Resources - Security & sanitization:
EnableHtmlSanitizer,AdditionalSanitizeAttributes,AdditionalSanitizeTags,DeniedSanitizeSelectors - Keyboard & shortcuts:
KeyConfigurewith fullShortcutKeysdefault bindings table - Persistence & auto-save:
EnablePersistence,SaveInterval,AutoSaveOnIdle - Undo/redo config:
UndoRedoSteps,UndoRedoTimer - HTTP integration:
HttpClientInstance - Full 38-property summary table
Data Binding & Value Management
📄 Read: references/data-binding.md
- Two-way binding with
@bind-Value - One-way binding and programmatic value updates
ValueChangeevent for detecting edits- Read-only mode (
Readonlyproperty) - Max length enforcement and character count display
Paste Cleanup
📄 Read: references/paste-and-cleanup.md
RichTextEditorPasteCleanupSettingsconfiguration- Stripping/keeping specific HTML attributes and styles on paste
- Forcing plain text paste
- Enter key behavior (
EnterKey,ShiftEnterKey) - Undo/redo manager configuration
Import & Export
📄 Read: references/import-export.md
- Importing Word documents into the editor
- Exporting content to Word (.docx) and PDF
- HTTP client configuration for import/export services
- Mail merge with dynamic data
- WebAssembly performance optimizations for large documents
Accessibility & Globalization
📄 Read: references/accessibility-globalization.md
- WCAG 2.1 compliance details
- Keyboard shortcuts and navigation reference
- ARIA roles and screen reader support
- RTL layout (
EnableRtl) - Localization and culture configuration
- XHTML validation
Common Patterns
Basic Smart Rich Text Editor with AI
@rendermode InteractiveServer
@using Syncfusion.Blazor.SmartRichTextEditor
<SfSmartRichTextEditor @bind-Value="@Content">
<AssistViewSettings Placeholder="Ask AI to rewrite or generate content." />
</SfSmartRichTextEditor>
@code {
private string Content { get; set; } = "<p>Start editing...</p>";
}AI with custom Smart Action commands
<SfSmartRichTextEditor>
<AssistViewSettings Commands="@MyCommands" Suggestions="@QuickSuggestions" />
</SfSmartRichTextEditor>
@code {
private List<AICommands> MyCommands = new()
{
new AICommands { Text = "Summarize", Prompt = "Summarize this content concisely" },
new AICommands { Text = "Expand", Prompt = "Add more details and examples" },
new AICommands
{
Text = "Translate",
Items = new List<AICommands>
{
new AICommands { Text = "To French", Prompt = "Translate to French" },
new AICommands { Text = "To Spanish", Prompt = "Translate to Spanish" }
}
}
};
private List<string> QuickSuggestions = new()
{
"Fix grammar", "Make shorter", "More formal", "Simplify"
};
}Programmatic AI popup control
<SfSmartRichTextEditor>
<AssistViewSettings @ref="AssistViewRef" MaxPromptHistory="10" />
</SfSmartRichTextEditor>
<button @onclick="OpenAI">Open AI</button>
<button @onclick="RunPrompt">Run Prompt</button>
@code {
private AssistViewSettings AssistViewRef;
private async Task OpenAI() =>
await AssistViewRef.ShowAIPopupAsync();
private async Task RunPrompt() =>
await AssistViewRef.ExecuteAIPromptAsync("Improve the clarity of this text");
}Two-way bound editor with character count
<SfSmartRichTextEditor @bind-Value="@HtmlContent" ShowCharCount="true" MaxLength="2000">
<AssistViewSettings Placeholder="Ask AI for writing help." />
</SfSmartRichTextEditor>
@code {
private string HtmlContent { get; set; } = string.Empty;
}Read-only display
<SfSmartRichTextEditor Value="@HtmlContent" Readonly="true">
<RichTextEditorToolbarSettings Enable="false" />
</SfSmartRichTextEditor>Markdown editor mode
<SfSmartRichTextEditor EditorMode="EditorMode.Markdown" @bind-Value="@MarkdownContent">
<AssistViewSettings Placeholder="Ask AI to help with your Markdown content." />
</SfSmartRichTextEditor>
@code {
private string MarkdownContent { get; set; } = "**Hello** world!";
}Handle AI prompt event to intercept requests
<SfSmartRichTextEditor>
<AssistViewSettings AIPromptRequested="OnAIPrompt" />
</SfSmartRichTextEditor>
@code {
private async Task OnAIPrompt(AssistViewPromptRequestedEventArgs args)
{
// Log, validate, or modify args.Prompt before it is sent to AI
Console.WriteLine($"Prompt: {args.Prompt}");
// To cancel: args.Cancel = true;
}
}Accessibility and Globalization
Table of Contents
- Accessibility Compliance Overview
- WAI-ARIA Attributes
- Keyboard Shortcuts Reference
- Custom Key Configuration
- RTL Support
- Localization
- XHTML Validation
---
Accessibility Compliance Overview
The Smart Rich Text Editor is built to comply with the following accessibility standards:
| Standard | Level / Status |
|---|---|
| WCAG 2.2 | AA |
| Section 508 | ✅ Full support |
| WAI-ARIA | ✅ Roles, states, properties applied |
| Screen Reader | ✅ Supported |
| Right-to-Left (RTL) | ✅ Supported |
| Keyboard Navigation | ✅ Full support |
| Color Contrast | ⚠️ Partial (some elements) |
| Mobile Device | ✅ Supported |
| Axe-core Validation | ✅ Passes automated checks |
---
WAI-ARIA Attributes
The toolbar element is assigned role="toolbar":
| Attribute | Value / Description |
|---|---|
role="toolbar" | Identifies the toolbar region |
aria-orientation | horizontal (default) |
aria-haspopup | true when popup mode is active |
aria-disabled | Reflects toolbar disabled state |
aria-owns | References the editor element ID from the toolbar popup |
The editor content area carries role="application":
| Attribute | Description |
|---|---|
role="application" | Marks the editing surface as an interactive application region |
aria-disabled | Reflects read-only/disabled state |
---
Keyboard Shortcuts Reference
Toolbar Navigation
| Action | Windows | Mac |
|---|---|---|
| Focus toolbar | Alt + F10 | ⌥ + F10 |
| Next tool | → | → |
| Previous tool | ← | ← |
| Execute focused tool | Enter / Space | Enter / Space |
| Close dropdown / dialog | Esc | Esc |
Content Editing and Formatting
| Action | Windows | Mac |
|---|---|---|
| Select all | Ctrl + A | ⌘ + A |
| Bold | Ctrl + B | ⌘ + B |
| Italic | Ctrl + I | ⌘ + I |
| Strikethrough | Ctrl + Shift + S | ⌘ + ⇧ + S |
| Inline code | Ctrl + ` | ⌘ + ` |
| Create link | Ctrl + K | ⌘ + K |
| New paragraph (hard break) | Enter | Enter |
| Soft line break | Shift + Enter | ⇧ + Enter |
| Copy format painter | Alt + Shift + C | ⌥ + ⌘ + C |
| Paste format painter | Alt + Shift + V | ⌥ + ⌘ + V |
| Clear format painter | Esc | Esc |
Text Case and Script
| Action | Windows | Mac |
|---|---|---|
| Uppercase | Ctrl + Shift + U | ⌘ + ⇧ + U |
| Lowercase | Ctrl + Shift + L | ⌘ + ⇧ + L |
| Superscript | Ctrl + Shift + = | ⌘ + ⇧ + = |
| Subscript | Ctrl + = | ⌘ + = |
Alignment and Indentation
| Action | Windows | Mac |
|---|---|---|
| Align left | Ctrl + L | ⌘ + L |
| Align centre | Ctrl + E | ⌘ + E |
| Align right | Ctrl + R | ⌘ + R |
| Justify | Ctrl + J | ⌘ + J |
| Increase indent | Ctrl + ] | ⌘ + ] |
| Decrease indent | Ctrl + [ | ⌘ + [ |
Lists
| Action | Windows | Mac |
|---|---|---|
| Ordered list | Ctrl + Shift + O | ⌘ + ⇧ + O |
| Unordered list | Ctrl + Alt + O | ⌘ + ⌥ + O |
Insert
| Action | Windows | Mac |
|---|---|---|
| Insert table dialog | Ctrl + Shift + E | ⌘ + ⇧ + E |
| Insert image dialog | Ctrl + Shift + I | ⌘ + ⇧ + I |
| Insert audio dialog | Ctrl + Shift + A | ⌘ + ⇧ + A |
| Insert video dialog | Ctrl + Alt + V | ⌘ + ⌥ + V |
Table Navigation
| Action | Windows | Mac |
|---|---|---|
| Next cell | Tab | Tab |
| Previous cell | Shift + Tab | ⇧ + Tab |
| Navigate cells | ↑ ↓ ← → | ↑ ↓ ← → |
| Insert new row (last cell) | Tab | Tab |
Clipboard
| Action | Windows | Mac |
|---|---|---|
| Copy | Ctrl + C | ⌘ + C |
| Cut | Ctrl + X | ⌘ + X |
| Paste | Ctrl + V | ⌘ + V |
| Paste as plain text | Ctrl + Shift + V | ⌘ + ⌥ + ⇧ + V |
Undo / Redo and Misc
| Action | Windows | Mac |
|---|---|---|
| Undo | Ctrl + Z | ⌘ + Z |
| Redo | Ctrl + Y | ⌘ + Y |
| View HTML source | Ctrl + Shift + H | ⌘ + ⇧ + H |
| Toggle fullscreen | Ctrl + Shift + F | ⌘ + ⇧ + F |
| Exit fullscreen | Esc | Esc |
| Clear all formatting | Ctrl + Shift + R | ⌘ + ⇧ + R |
---
Custom Key Configuration
Override default shortcuts with KeyConfigure:
<SfSmartRichTextEditor KeyConfigure="@Keys">
<p>Bold is now Ctrl+1, Italic is Ctrl+2.</p>
</SfSmartRichTextEditor>
@code {
private ShortcutKeys Keys = new()
{
Bold = "ctrl+1",
Italic = "ctrl+2"
};
}UseShortcutKeysproperties matching theCommandNameactions you want to override. Unspecified keys keep their defaults.
---
RTL Support
Enable right-to-left layout for Arabic, Hebrew, and other RTL languages:
<SfSmartRichTextEditor EnableRtl="true">
<p dir="rtl">محتوى باللغة العربية</p>
</SfSmartRichTextEditor>EnableRtl does not change automatically based on the browser culture — set it explicitly when needed.---
Localization
The RTE participates in Syncfusion's standard Blazor localization pipeline. Register resource strings in Program.cs:
// Program.cs (Blazor Server)
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
builder.Services.AddSyncfusionBlazor();
var app = builder.Build();
app.UseRequestLocalization(new RequestLocalizationOptions()
.SetDefaultCulture("ar")
.AddSupportedCultures("en-US", "ar", "de")
.AddSupportedUICultures("en-US", "ar", "de"));Refer to the Syncfusion Blazor Localization guide for adding locale resource files.
---
XHTML Validation
Enable EnableXhtml to continuously validate the editor's content against XHTML rules. Invalid constructs are automatically removed:
<SfSmartRichTextEditor EnableXhtml="true">
<p>Content is continuously validated as you type.</p>
</SfSmartRichTextEditor>What is validated:
| Rule | Detail |
|---|---|
| Attribute case | All attributes must be lowercase |
| Quoted values | Attribute values must be in quotation marks |
| Valid attributes | Only spec-valid attributes per element |
| Required attributes | Missing required attributes are flagged |
| Tag case | All HTML tags must be lowercase |
| Proper closing | Every opening tag must have a matching close |
| Valid elements | Unknown elements are removed |
| Nesting | Inline elements cannot wrap block elements |
| Single root | Content must have one root element |
CombineEnableXhtml="true"withEnableHtmlSanitizer="true"(the default) for maximum security when displaying user-generated content.
``
AI Assistant Popup Appearance & CSS
Customize the AI Assistant popup using CSS class selectors. All styles target the .e-rte-aiquery-dialog container.
CSS Selectors Reference
| Selector | Targets |
|---|---|
.e-rte-aiquery-dialog | Outermost popup container |
.e-rte-aiquery-dialog .e-aiassistview | Main AI assistant view panel |
.e-rte-aiquery-dialog .e-aiassistview .e-view-header .e-toolbar | Header toolbar |
.e-rte-aiquery-dialog .e-aiassistview .e-view-header .e-toolbar-items | Header toolbar items |
.e-rte-aiquery-dialog .e-aiassistview .e-view-content .e-toolbar | Content area toolbar |
.e-rte-aiquery-dialog .e-aiassistview .e-view-content .e-toolbar .e-toolbar-items | Content toolbar items |
.e-rte-aiquery-dialog .e-aiassistview .e-view-content .e-toolbar .e-toolbar-item | Individual content toolbar item |
.e-rte-aiquery-dialog .e-aiassistview .e-view-content .e-footer | Footer / prompt input area |
---
Basic Popup Style Override
.e-rte-aiquery-dialog.e-dlg-modal.e-popup {
color: white;
background: white;
z-index: 1;
}---
Complete Custom Popup Styling Example
Targets individual sub-sections for fine-grained control:
@using Syncfusion.Blazor.SmartRichTextEditor
<SfSmartRichTextEditor Height="300" />
<style>
/* Main panel */
.e-rte-aiquery-dialog .e-aiassistview {
border-color: #e0e0e0;
background-color: #f4f4f4;
box-shadow: 3px 3px 10px 0px rgba(0, 0, 0, 0.2);
}
/* Header toolbar background */
.e-rte-aiquery-dialog .e-aiassistview .e-view-header .e-toolbar,
.e-rte-aiquery-dialog .e-aiassistview .e-view-header .e-toolbar-items {
background: #d5d5d5;
}
/* Content toolbar background */
.e-rte-aiquery-dialog .e-aiassistview .e-view-content .e-toolbar,
.e-rte-aiquery-dialog .e-aiassistview .e-view-content .e-toolbar .e-toolbar-items,
.e-rte-aiquery-dialog .e-aiassistview .e-view-content .e-toolbar .e-toolbar-item {
background: #f4f4f4;
}
/* Footer / input area border */
.e-rte-aiquery-dialog .e-aiassistview .e-view-content .e-footer {
border: 3px solid #e0e0e0;
}
</style>---
Tips
- Use
.e-rte-aiquery-dialogas the outermost scoping selector to avoid affecting other Syncfusion popups on the page. - For dark-mode themes, pair these overrides with the
[data-theme="dark"]attribute selector. - The popup respects
PopupWidthandPopupMaxHeightproperties set on<AssistViewSettings>— use those for sizing and CSS for visual styling.
AI Backend Configuration
Table of Contents
All backends follow the same pattern: install NuGet packages → create IChatClient → register with AddChatClient() → register SyncfusionAIService.
---
OpenAI
Prerequisites
- Active OpenAI account and API key from platform.openai.com
Supported Models
| Model | Notes |
|---|---|
gpt-4-turbo | Most capable, latest |
gpt-4 | Advanced reasoning |
gpt-3.5-turbo | Fast, cost-effective |
gpt-3.5-turbo-16k | Extended context |
NuGet Packages
Install-Package Microsoft.Extensions.AI
Install-Package Microsoft.Extensions.AI.OpenAIProgram.cs
using Syncfusion.Blazor;
using Syncfusion.Blazor.AI;
using Microsoft.Extensions.AI;
using OpenAI;
builder.Services.AddSyncfusionBlazor();
string openAIApiKey = "YOUR_API_KEY"; // Use env vars or User Secrets in production
string openAIModel = "gpt-4";
OpenAIClient openAIClient = new OpenAIClient(openAIApiKey);
IChatClient chatClient = openAIClient.GetChatClient(openAIModel).AsIChatClient();
builder.Services.AddChatClient(chatClient);
builder.Services.AddSingleton<IChatInferenceService, SyncfusionAIService>();Secure Key Storage
Environment variable (Windows):
$env:OPENAI_API_KEY = "your-api-key"Read from environment:
string openAIApiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")
?? throw new InvalidOperationException("OpenAI API key not found");User Secrets (development):
dotnet user-secrets set "OpenAI:ApiKey" "your-api-key"string openAIApiKey = builder.Configuration["OpenAI:ApiKey"];Troubleshooting
| Error | Fix |
|---|---|
| 401 Unauthorized | Verify API key is correct and not expired |
| 429 Too Many Requests | Reduce request frequency; check usage limits |
| Model not found | Verify model name at openai.com/docs/models |
---
Azure OpenAI
Prerequisites
- Active Azure subscription with Azure OpenAI resource deployed
- Deployed model (e.g.,
gpt-4,gpt-35-turbo) - Endpoint URL, API key, and deployment name from Azure Portal
Deploy a Model
1. Sign in to Azure Portal → Create Azure OpenAI resource 2. Go to Azure AI Studio → Deployments → Create new deployment 3. Configure: deployment name, model (e.g., gpt-35-turbo), version 4. Copy Endpoint and Key from Keys and Endpoint in your resource
Supported Models
| Model | Deployment Name | Use Case |
|---|---|---|
| GPT-4 | gpt-4 | Complex reasoning, high quality |
| GPT-4 Turbo | gpt-4-turbo | Latest capabilities |
| GPT-3.5 Turbo | gpt-35-turbo | Fast, cost-effective |
NuGet Packages
Install-Package Microsoft.Extensions.AI
Install-Package Microsoft.Extensions.AI.OpenAI
Install-Package Azure.AI.OpenAIProgram.cs
using Syncfusion.Blazor;
using Syncfusion.Blazor.AI;
using Azure.AI.OpenAI;
using Microsoft.Extensions.AI;
using System.ClientModel;
builder.Services.AddSyncfusionBlazor();
string azureOpenAIKey = "AZURE_OPENAI_KEY";
string azureOpenAIEndpoint = "https://your-resource.openai.azure.com/";
string azureOpenAIDeployment = "your-deployment-name";
AzureOpenAIClient azureClient = new AzureOpenAIClient(
new Uri(azureOpenAIEndpoint),
new ApiKeyCredential(azureOpenAIKey)
);
IChatClient chatClient = azureClient.GetChatClient(azureOpenAIDeployment).AsIChatClient();
builder.Services.AddChatClient(chatClient);
builder.Services.AddSingleton<IChatInferenceService, SyncfusionAIService>();Reading from appsettings.json (recommended)
{
"AzureOpenAI": {
"Key": "your-azure-key",
"Endpoint": "https://your-resource.openai.azure.com/",
"DeploymentName": "your-deployment-name"
}
}string azureOpenAIKey = builder.Configuration["AzureOpenAI:Key"];
string azureOpenAIEndpoint = builder.Configuration["AzureOpenAI:Endpoint"];
string azureOpenAIDeployment = builder.Configuration["AzureOpenAI:DeploymentName"];Managed Identity (Production Recommended)
using Azure.Identity;
var credential = new DefaultAzureCredential();
AzureOpenAIClient azureClient = new AzureOpenAIClient(
new Uri(azureOpenAIEndpoint),
credential
);Security & Compliance Features
- Virtual Network support and private endpoints
- Azure AD / RBAC integration
- HIPAA and SOC 2 compliance
- Data residency options
- Azure Monitor integration (requests/minute, token usage, latency, error rates)
Troubleshooting
| Error | Fix |
|---|---|
| ResourceNotFound (404) | Verify endpoint URL and resource name |
| InvalidAuthenticationTokenTenant (401) | Verify API key and region |
| Model not found (404) | Check deployment name and active status |
| Timeout | Check Azure OpenAI resource capacity |
---
Ollama (Local / Self-hosted)
Runs open-source LLMs locally — no API costs, no cloud connectivity required.
Install Ollama
Windows: Download installer from ollama.com macOS: Download .dmg, drag to Applications Linux: curl https://ollama.ai/install.sh | sh
Verify installation: ollama --version
Pull a Model
ollama pull mistral # Fast, good quality
ollama pull llama2 # General purpose
ollama pull orca-mini # Lightweight, very fast
ollama pull neural-chat # ConversationalStart Ollama Service
ollama serve # macOS/Linux (Windows starts automatically)Access at http://localhost:11434
NuGet Packages
Install-Package Microsoft.Extensions.AI
Install-Package OllamaSharpProgram.cs
using Syncfusion.Blazor;
using Syncfusion.Blazor.AI;
using Microsoft.Extensions.AI;
using OllamaSharp;
builder.Services.AddSyncfusionBlazor();
string modelName = "mistral"; // any model you pulled
string ollamaUrl = "http://localhost:11434";
IChatClient chatClient = new OllamaApiClient(ollamaUrl, modelName);
builder.Services.AddChatClient(chatClient);
builder.Services.AddSingleton<IChatInferenceService, SyncfusionAIService>();Docker Compose Deployment
version: '3.8'
services:
ollama:
image: ollama/ollama:latest
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
environment:
- OLLAMA_HOST=0.0.0.0:11434
volumes:
ollama_data:Pull models inside container:
docker exec -it <container-id> ollama pull mistralModel Recommendations
| Use Case | Model | Notes |
|---|---|---|
| General editing | mistral | Fast, good quality |
| Content creation | llama2 | Balanced performance |
| Lightweight / fast | orca-mini | Very fast, limited capability |
| Best quality | dolphin-mixtral | Excellent, resource-heavy |
GPU Acceleration
- NVIDIA: Install CUDA toolkit
- AMD: Install ROCm
- Intel: Install Intel oneAPI
Troubleshooting
| Problem | Fix |
|---|---|
| Unable to connect | Run curl http://localhost:11434/api/tags to verify; check ollama serve is running |
| Model not found | Run ollama list; pull with ollama pull <model> |
| Out of memory | Use smaller models (orca-mini, mistral); restart Ollama |
| Slow responses | Enable GPU acceleration; use faster models |
---
Custom IChatClient
Integrate any proprietary or internal AI service by implementing the IChatClient interface from Microsoft.Extensions.AI.
Step 1: Implement IChatClient
using Microsoft.Extensions.AI;
namespace YourApp.AI
{
public class CustomAIBackend : IChatClient
{
private readonly string _endpoint;
private readonly string _apiKey;
private readonly HttpClient _httpClient;
public CustomAIBackend(string endpoint, string apiKey)
{
_endpoint = endpoint;
_apiKey = apiKey;
_httpClient = new HttpClient();
}
public async ValueTask<ChatCompletion> CompleteAsync(
IList<ChatMessage> chatMessages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
var requestBody = new
{
messages = chatMessages.Select(m => new {
role = m.Role.ToString().ToLower(),
content = m.Content?[0]?.Text ?? string.Empty
}),
max_tokens = options?.MaxCompletionTokens ?? 500,
temperature = options?.Temperature ?? 0.7f
};
var request = new HttpRequestMessage(HttpMethod.Post, _endpoint)
{
Content = new StringContent(
System.Text.Json.JsonSerializer.Serialize(requestBody),
System.Text.Encoding.UTF8,
"application/json"
)
};
if (!string.IsNullOrEmpty(_apiKey))
request.Headers.Add("Authorization", $"Bearer {_apiKey}");
var response = await _httpClient.SendAsync(request, cancellationToken);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var result = System.Text.Json.JsonSerializer
.Deserialize<CustomResponse>(content);
return new ChatCompletion(new ChatMessage(
ChatRole.Assistant,
result?.output ?? "No response"
));
}
public void Dispose() => _httpClient?.Dispose();
private class CustomResponse { public string? output { get; set; } }
}
}Step 2: Register in Program.cs
using Syncfusion.Blazor;
using Syncfusion.Blazor.AI;
using YourApp.AI;
builder.Services.AddSyncfusionBlazor();
var customBackend = new CustomAIBackend(
"https://your-ai-service.com/api/inference",
"your-api-key"
);
builder.Services.AddChatClient(customBackend);
builder.Services.AddSingleton<IChatInferenceService, SyncfusionAIService>();With IConfiguration Support
// appsettings.json
{
"CustomAI": {
"Endpoint": "https://your-ai-service.com/api/inference",
"ApiKey": "your-api-key"
}
}
// In constructor
public CustomAIBackend(IConfiguration configuration)
{
_endpoint = configuration["CustomAI:Endpoint"]
?? throw new InvalidOperationException("CustomAI:Endpoint not configured");
_apiKey = configuration["CustomAI:ApiKey"]
?? throw new InvalidOperationException("CustomAI:ApiKey not configured");
_httpClient = new HttpClient();
}Streaming Responses
For streaming UX, read SSE (Server-Sent Events) chunks and call UpdateAIResponseAsync on AssistViewSettings:
public async ValueTask<ChatCompletion> CompleteAsync(
IList<ChatMessage> chatMessages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
var request = new HttpRequestMessage(HttpMethod.Post, _endpoint);
request.Content = new StringContent(
System.Text.Json.JsonSerializer.Serialize(new { messages = chatMessages }),
System.Text.Encoding.UTF8, "application/json"
);
request.Headers.Add("Accept", "text/event-stream");
var response = await _httpClient.SendAsync(
request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
using var reader = new System.IO.StreamReader(stream);
var fullContent = new System.Text.StringBuilder();
while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync();
if (line?.StartsWith("data: ") == true)
{
var chunk = System.Text.Json.JsonSerializer
.Deserialize<StreamChunk>(line.Substring(6));
if (chunk?.content != null) fullContent.Append(chunk.content);
}
}
return new ChatCompletion(new ChatMessage(
ChatRole.Assistant, fullContent.ToString()
));
}
private class StreamChunk { public string? content { get; set; } }Retry Logic
public async ValueTask<ChatCompletion> CompleteAsync(
IList<ChatMessage> chatMessages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
int maxRetries = 3;
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
try
{
return await AttemptCompletionAsync(chatMessages, cancellationToken);
}
catch (HttpRequestException) when (attempt < maxRetries)
{
await Task.Delay(TimeSpan.FromSeconds(attempt * 2), cancellationToken);
}
}
throw new InvalidOperationException("Failed after max retries");
}AssistViewSettings Events
Table of Contents
All events are bound directly on the <AssistViewSettings> child component.
---
AIPromptRequested
Type: EventCallback<AssistViewPromptRequestedEventArgs> Namespace: Syncfusion.Blazor.InteractiveChat
Fires when the user submits a prompt. Use this to intercept, modify, or cancel the prompt before it reaches the AI service.
EventArgs properties:
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to prevent the prompt from being sent to AI |
Prompt | string | The user's prompt text (can be modified) |
Response | string | Set a pre-built response to skip the AI call entirely |
PromptSuggestions | List<string> | Override suggestion chips for the next turn |
ResponseToolbarItems | List<AssistViewToolbarItem> | Override toolbar items shown on the response |
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.InteractiveChat
<SfSmartRichTextEditor>
<AssistViewSettings AIPromptRequested="OnAIPrompt" />
</SfSmartRichTextEditor>
@code {
private async Task OnAIPrompt(AssistViewPromptRequestedEventArgs args)
{
// Log or audit the prompt
Console.WriteLine($"Prompt: {args.Prompt}");
// To cancel the AI call:
// args.Cancel = true;
// To short-circuit with a pre-built response:
// args.Response = "Here is a predefined answer.";
}
}---
AIResponseStopped
Type: EventCallback<ResponseStoppedEventArgs> Namespace: Syncfusion.Blazor.InteractiveChat
Fires when the user clicks the "Stop Responding" button during an active AI stream.
EventArgs properties:
| Property | Type | Description |
|---|---|---|
DataIndex | int | Zero-based index of the active prompt in the conversation. -1 = not applicable |
Prompt | string | The prompt text that was being responded to |
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.InteractiveChat
<SfSmartRichTextEditor>
<AssistViewSettings AIResponseStopped="OnResponseStopped" />
</SfSmartRichTextEditor>
@code {
private async Task OnResponseStopped(ResponseStoppedEventArgs args)
{
Console.WriteLine($"Stopped at index {args.DataIndex}, prompt: {args.Prompt}");
}
}---
AIToolbarItemClicked
Type: EventCallback<AssistViewToolbarItemClickedEventArgs> Namespace: Syncfusion.Blazor.InteractiveChat
Fires when the user clicks a custom toolbar item inside the AI popup (header, prompt, or response toolbars).
EventArgs properties:
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to cancel the default click action |
DataIndex | int | Index of the AI response item. -1 = not applicable |
Event | MouseEventArgs | The underlying mouse event |
Item | AssistViewToolbarItem | The clicked toolbar item (contains Text, IconCss, Tooltip, etc.) |
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.InteractiveChat
<SfSmartRichTextEditor>
<AssistViewSettings AIToolbarItemClicked="OnToolbarClick" />
</SfSmartRichTextEditor>
@code {
private async Task OnToolbarClick(AssistViewToolbarItemClickedEventArgs args)
{
if (args.Item.Text == "Insert")
{
// Handle custom "Insert" button click
Console.WriteLine("Insert clicked");
}
}
}---
AIPopupOpening
Type: EventCallback<BeforeOpenEventArgs> Namespace: Syncfusion.Blazor.Popups
Fires before the AI Assistant popup opens. Set args.Cancel = true to prevent it from opening (e.g., for validation or access control).
EventArgs properties:
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to prevent the popup from opening |
Element | ElementReference | Reference to the popup DOM element |
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.Popups
<SfSmartRichTextEditor>
<AssistViewSettings AIPopupOpening="OnPopupOpening" />
</SfSmartRichTextEditor>
@code {
private async Task OnPopupOpening(BeforeOpenEventArgs args)
{
// Prevent opening if user is not authenticated
if (!UserIsAuthenticated)
{
args.Cancel = true;
}
}
private bool UserIsAuthenticated => true; // Replace with real check
}---
AIPopupClosing
Type: EventCallback<BeforeCloseEventArgs> Namespace: Syncfusion.Blazor.Popups
Fires before the AI Assistant popup closes. Use to prompt the user to save work or confirm exit.
EventArgs properties:
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to prevent the popup from closing |
ClosedBy | string | Reason for close: "CloseIcon", "Escape", "OverlayClick" |
Event | EventArgs | The underlying event that triggered the close |
IsInteracted | bool | true if triggered by user interaction; false if programmatic |
PreventFocus | bool | When true, suppresses focus restoration after close |
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.Popups
<SfSmartRichTextEditor>
<AssistViewSettings AIPopupClosing="OnPopupClosing" />
</SfSmartRichTextEditor>
@code {
private async Task OnPopupClosing(BeforeCloseEventArgs args)
{
// Block accidental Escape key closing
if (args.ClosedBy == "Escape" && args.IsInteracted)
{
args.Cancel = true;
}
}
}AssistViewSettings Methods
All methods are async (Task-returning). Obtain a reference via @ref on <AssistViewSettings>.
Table of Contents
- Setup: Getting a Reference
- ShowAIPopupAsync
- HideAIPopupAsync
- ExecuteAIPromptAsync
- UpdateAIResponseAsync
- GetAIPromptHistoryAsync
- ClearAIPromptHistoryAsync
- Complete Example
---
Setup: Getting a Reference
<SfSmartRichTextEditor>
<AssistViewSettings @ref="AssistViewRef" Placeholder="Ask AI..." />
</SfSmartRichTextEditor>
@code {
private AssistViewSettings AssistViewRef;
}---
ShowAIPopupAsync
Signature: Task ShowAIPopupAsync()
Opens the AI Assistant popup and starts a new conversation session.
private async Task OpenPopup()
{
await AssistViewRef.ShowAIPopupAsync();
}---
HideAIPopupAsync
Signature: Task HideAIPopupAsync()
Closes the AI Assistant popup.
private async Task ClosePopup()
{
await AssistViewRef.HideAIPopupAsync();
}---
ExecuteAIPromptAsync
Signature: Task ExecuteAIPromptAsync(string prompt)
Sends a prompt to the AI as if the user typed and submitted it. Useful for automating AI workflows from buttons or application logic.
Parameters:
prompt— the text to send
private async Task RunAutoPrompt()
{
await AssistViewRef.ExecuteAIPromptAsync("Write a professional summary about AI in healthcare");
}---
UpdateAIResponseAsync
Signature: Task UpdateAIResponseAsync(string outputResponse, bool isFinalUpdate = false)
Streams or injects text into the current AI response display. Call repeatedly with chunks while streaming; set isFinalUpdate = true when streaming is complete (this hides the "Stop" button).
Parameters:
outputResponse— a text chunk or the full response stringisFinalUpdate—truesignals that streaming is finished (default:false)
// Inject a full custom response at once
private async Task InjectCustomResponse()
{
string response = "This is a custom AI-generated response injected programmatically.";
await AssistViewRef.UpdateAIResponseAsync(response, isFinalUpdate: true);
}
// Simulate streaming in chunks
private async Task StreamResponse()
{
string[] chunks = { "This is ", "a streamed ", "response." };
foreach (var chunk in chunks)
{
await AssistViewRef.UpdateAIResponseAsync(chunk);
await Task.Delay(100); // simulate streaming delay
}
await AssistViewRef.UpdateAIResponseAsync("", isFinalUpdate: true);
}---
GetAIPromptHistoryAsync
Signature: Task<AssistViewPrompt[]> GetAIPromptHistoryAsync()
Returns all saved prompts and responses from the conversation history in chronological order (oldest first). History is capped at MaxPromptHistory (default: 20).
Returns: AssistViewPrompt[] with fields:
Prompt—string: original user promptResponse—string: AI response (Markdown converted to HTML)IsResponseHelpful—bool?: user feedback flagAttachedFiles—List<AssistViewAttachment>?: files attached to the prompt
private async Task ExportHistory()
{
AssistViewPrompt[] history = await AssistViewRef.GetAIPromptHistoryAsync();
foreach (var entry in history)
{
Console.WriteLine($"Q: {entry.Prompt}");
Console.WriteLine($"A: {entry.Response}");
}
}---
ClearAIPromptHistoryAsync
Signature: Task ClearAIPromptHistoryAsync()
Deletes all conversation history and resets the AI popup to a clean state.
private async Task ClearHistory()
{
await AssistViewRef.ClearAIPromptHistoryAsync();
}---
Complete Example
Demonstrates all six methods wired to buttons:
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.InteractiveChat
@using Syncfusion.Blazor.Buttons
<div style="display: flex; gap: 8px; padding-bottom: 15px; flex-wrap: wrap;">
<SfButton @onclick="ShowPopup">Show Popup</SfButton>
<SfButton @onclick="ExecutePrompt">Execute Prompt</SfButton>
<SfButton @onclick="InjectResponse">Inject Response</SfButton>
<SfButton @onclick="GetHistory">Get History</SfButton>
<SfButton @onclick="ClearHistory">Clear History</SfButton>
<SfButton @onclick="HidePopup">Hide Popup</SfButton>
</div>
<SfSmartRichTextEditor>
<AssistViewSettings @ref="AssistViewRef"
Placeholder="Ask AI to enhance your content..."
MaxPromptHistory="10" />
</SfSmartRichTextEditor>
@code {
private AssistViewSettings AssistViewRef;
private async void ShowPopup() => await AssistViewRef.ShowAIPopupAsync();
private async void HidePopup() => await AssistViewRef.HideAIPopupAsync();
private async void ClearHistory() => await AssistViewRef.ClearAIPromptHistoryAsync();
private async void ExecutePrompt()
{
await AssistViewRef.ExecuteAIPromptAsync("Write a professional summary about AI");
}
private async void InjectResponse()
{
await AssistViewRef.UpdateAIResponseAsync(
"This is a custom response injected via UpdateAIResponseAsync().",
isFinalUpdate: true
);
}
private async void GetHistory()
{
AssistViewPrompt[] history = await AssistViewRef.GetAIPromptHistoryAsync();
foreach (var item in history)
Console.WriteLine($"[{item.Prompt}] → [{item.Response}]");
}
}AssistViewSettings Properties
Table of Contents
- Commands
- PopupMaxHeight / PopupWidth
- Placeholder
- Prompts
- Suggestions
- MaxPromptHistory
- BannerTemplate
- HeaderToolbarSettings
- PromptToolbarSettings
- ResponseToolbarSettings
---
Commands
Type: List<AICommands> Default: empty list
Predefined AI actions displayed in the Smart Action dropdown toolbar. Each AICommands entry supports:
Text— display label shown in the UIPrompt— text sent to the AI when selected (the editor automatically appends " for the selected content" or " for the document content" as context)IconCss— optional CSS class for an iconItems— nestedList<AICommands>for multi-level sub-menus (recursive)
Important: The system automatically appends contextual information to your prompt. Do not end your Prompt with a period (.) if you want clean formatting, as it will result in ". for the selected content" instead of " for the selected content".
@using Syncfusion.Blazor.SmartRichTextEditor
<SfSmartRichTextEditor>
<AssistViewSettings Commands="@MyCommands" />
</SfSmartRichTextEditor>
@code {
private List<AICommands> MyCommands = new()
{
// ✓ Correct: No period at the end - results in "Make this shorter for the selected content"
new AICommands { Text = "Shorten", Prompt = "Make this shorter" },
// ✓ Correct: No period - results in "Add more details for the selected content"
new AICommands { Text = "Expand", Prompt = "Add more details" },
// ✗ Avoid: Ending with period - results in "Improve clarity. for the selected content"
// new AICommands { Text = "Improve", Prompt = "Improve clarity." },
new AICommands
{
Text = "Translate",
Items = new List<AICommands>
{
new AICommands { Text = "To French", Prompt = "Translate to French" },
new AICommands { Text = "To Spanish", Prompt = "Translate to Spanish" }
}
}
};
}The AI prompt automatically includes editor context (selected text or full document) — you do not need to add {{selection}} placeholders. The system appends " for the selected content" or " for the document content" to your prompt automatically.---
PopupMaxHeight / PopupWidth
PopupMaxHeight — string — default: "400" (pixels) PopupWidth — string — default: "600" (pixels)
Control the size of the AI Assistant popup. Accepts CSS values ("80vh", "650px") or plain numbers treated as pixels.
<SfSmartRichTextEditor>
<AssistViewSettings PopupMaxHeight="80vh" PopupWidth="650px" />
</SfSmartRichTextEditor>---
Placeholder
Type: string Default: "Ask AI to rewrite or generate content."
Placeholder text shown in the AI prompt textarea when empty.
<SfSmartRichTextEditor>
<AssistViewSettings Placeholder="How can I improve this document?" />
</SfSmartRichTextEditor>---
Prompts
Type: List<AssistViewPrompt> Default: empty list
Preloads the AI conversation with predefined prompt/response pairs. Useful for starter workflows or demonstration content.
AssistViewPrompt fields:
Prompt—string: the user prompt textResponse—string: the pre-set AI response (supports Markdown/HTML)
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.InteractiveChat
<SfSmartRichTextEditor>
<AssistViewSettings Prompts="@TemplatePrompts" />
</SfSmartRichTextEditor>
@code {
private List<AssistViewPrompt> TemplatePrompts = new()
{
new AssistViewPrompt
{
Prompt = "Draft a professional email",
Response = "Subject: Hello Team\n\nDear Team,\n\nI hope this message finds you well.\n\nBest regards"
},
new AssistViewPrompt
{
Prompt = "Create API documentation",
Response = "### GET /users\nRetrieves a list of users.\n\n**Request**\nGET /api/users"
}
};
}---
Suggestions
Type: List<string> Default: empty list
Quick-access suggestion chips displayed in the AI popup. Clicking a chip sends it as a prompt instantly.
@using Syncfusion.Blazor.SmartRichTextEditor
<SfSmartRichTextEditor>
<AssistViewSettings Suggestions="@QuickSuggestions" />
</SfSmartRichTextEditor>
@code {
private List<string> QuickSuggestions = new()
{
"Make shorter",
"Improve clarity",
"Fix grammar",
"Add examples",
"More formal",
"Simplify"
};
}---
MaxPromptHistory
Type: int Default: 20
Maximum conversation entries retained in the popup history. When exceeded, oldest entries are removed automatically. History persists across open/close cycles of the popup.
<SfSmartRichTextEditor>
<!-- Keep only 5 recent conversations -->
<AssistViewSettings MaxPromptHistory="5" />
</SfSmartRichTextEditor>---
BannerTemplate
Type: RenderFragment Default: none
Custom template for the banner area at the top of the AI popup. Use for branding, status messages, or usage instructions.
@using Syncfusion.Blazor.SmartRichTextEditor
<SfSmartRichTextEditor>
<AssistViewSettings>
<BannerTemplate>
<div style="padding: 16px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;">
<h3 style="margin: 0;">Smart AI Assistant</h3>
<span style="font-size: 12px;">Real-time AI assistance</span>
</div>
</BannerTemplate>
</AssistViewSettings>
</SfSmartRichTextEditor>---
HeaderToolbarSettings
Type: RenderFragment Default: none
Configures toolbar items in the header section of the AI popup.
Each AssistViewToolbarItem supports:
| Property | Type | Default |
|---|---|---|
Text | string | String.Empty |
IconCss | string | String.Empty |
Tooltip | string | "" |
Type | ItemType | ItemType.Button |
CssClass | string | "" |
Disabled | bool | false |
Visible | bool | true |
TabIndex | int | — |
Template | RenderFragment | null |
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.InteractiveChat
@using Syncfusion.Blazor.Navigations
<SfSmartRichTextEditor>
<AssistViewSettings>
<HeaderToolbarSettings>
<AssistViewToolbarItem Type="ItemType.Spacer" />
<AssistViewToolbarItem Text="Close" IconCss="e-icons e-close" />
<AssistViewToolbarItem Text="AI Commands" />
</HeaderToolbarSettings>
</AssistViewSettings>
</SfSmartRichTextEditor>---
PromptToolbarSettings
Type: RenderFragment Default: none
Configures toolbar items below the prompt input area.
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.InteractiveChat
@using Syncfusion.Blazor.Navigations
<SfSmartRichTextEditor>
<AssistViewSettings>
<PromptToolbarSettings>
<PromptToolbarItem Text="Edit" IconCss="e-icons e-assist-edit" Tooltip="Edit prompt" />
<PromptToolbarItem Text="Copy" IconCss="e-icons e-assist-copy" Tooltip="Copy to clipboard" />
<PromptToolbarItem Type="ItemType.Separator" />
<PromptToolbarItem Text="Save" IconCss="e-icons e-save" />
</PromptToolbarSettings>
</AssistViewSettings>
</SfSmartRichTextEditor>---
ResponseToolbarSettings
Type: RenderFragment Default: none
Configures toolbar items in the AI response viewer section. Supports Template for fully custom buttons.
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.InteractiveChat
@using Syncfusion.Blazor.Navigations
<SfSmartRichTextEditor>
<AssistViewSettings>
<ResponseToolbarSettings>
<ResponseToolbarItem Text="Regenerate" IconCss="e-icons e-refresh" />
<ResponseToolbarItem Text="Copy" IconCss="e-icons e-copy" />
<ResponseToolbarItem Type="ItemType.Separator" />
<ResponseToolbarItem Text="Insert" IconCss="e-icons e-check" />
<ResponseToolbarItem>
<Template>
<button onclick="alert('Feedback saved')">👍 Helpful</button>
</Template>
</ResponseToolbarItem>
</ResponseToolbarSettings>
</AssistViewSettings>
</SfSmartRichTextEditor>Built-in Toolbar Tools Reference
Table of Contents
- Default Toolbar
- AI-Specific Toolbar Items
- Text Formatting Tools
- Font and Styling Tools
- Alignment Tools
- Lists and Indentation
- Hyperlink Tools
- Image Quick Toolbar Commands
- Table Quick Toolbar Commands
- Utility Tools
- Removing Default Tools
---
Default Toolbar
Out of the box, the Smart Rich Text Editor renders these toolbar items when no Items list is specified:
Bold | Italic | Underline | | Formats | Alignments | Blockquote | OrderedList | UnorderedList | | CreateLink | Image | | SourceCode | Undo | Redo
---
AI-Specific Toolbar Items
SfSmartRichTextEditor provides two built-in AI toolbar buttons that are not part of the ToolbarCommand enum. They must be added using the Name property on ToolbarItemModel.
Name value | Renders | Behaviour |
|---|---|---|
"AI Commands" | Smart Action dropdown button | Shows the AI command menu (Summarize, Expand, Fix Grammar, Change Tone, etc.) for the selected text. Configured via AssistViewSettings.Commands. |
"AI Query" | Ask AI button | Opens the AI Query dialog popup (same as pressing Alt+Enter). |
Critical: UsingToolbarCommandenum values will not render these buttons. You must useName = "AI Commands"andName = "AI Query"exactly (case-sensitive).
Example — adding AI buttons to a custom toolbar
<SfSmartRichTextEditor>
<RichTextEditorToolbarSettings Items="@Tools" />
<AssistViewSettings Commands="@AiCommands"
Placeholder="How can I help?" />
</SfSmartRichTextEditor>
@code {
private List<ToolbarItemModel> Tools = new()
{
// ⬇ AI-specific items — MUST use Name, not Command; place first for visibility
new() { Name = "AI Commands" },
new() { Name = "AI Query" },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.Bold },
new() { Command = ToolbarCommand.Italic },
new() { Command = ToolbarCommand.Underline },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.Formats },
new() { Command = ToolbarCommand.Alignments },
new() { Command = ToolbarCommand.OrderedList },
new() { Command = ToolbarCommand.UnorderedList },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.Undo },
new() { Command = ToolbarCommand.Redo }
};
private List<AICommands> AiCommands = new()
{
new() { Text = "Improve Writing", Prompt = "Improve the clarity and quality of this text." },
new() { Text = "Fix Grammar", Prompt = "Fix all grammar and spelling errors." },
new() { Text = "Summarize", Prompt = "Summarize this content concisely." },
new() { Text = "Expand", Prompt = "Expand this with more detail and examples." }
};
}If you omitName = "AI Commands"andName = "AI Query"fromItems, the Smart Action dropdown and Ask AI button will not appear in the toolbar even thoughAssistViewSettingsis configured.
---
Text Formatting Tools
ToolbarCommand | Effect |
|---|---|
Bold | Makes selected text bold (<strong>) |
Italic | Italicises selected text (<em>) |
Underline | Underlines selected text |
StrikeThrough | Applies strikethrough |
InlineCode | Wraps selection in <code> |
SubScript | Subscript — positions text lower |
SuperScript | Superscript — positions text higher |
LowerCase | Converts selection to lowercase |
UpperCase | Converts selection to uppercase |
ClearFormat | Strips all inline styles from selection |
---
Font and Styling Tools
ToolbarCommand | Effect |
|---|---|
FontName | Font family dropdown |
FontSize | Font size dropdown |
FontColor | Font colour picker |
BackgroundColor | Highlight / background colour picker |
Formats | Paragraph/heading format dropdown (P, H1–H6, Pre, BlockQuote) |
LineHeight | Line-height dropdown; applies to parent block |
---
Alignment Tools
ToolbarCommand | Effect |
|---|---|
Alignments | Combined alignment dropdown |
JustifyLeft | Left-align |
JustifyCenter | Centre-align |
JustifyRight | Right-align |
JustifyFull | Justify |
Alignment is applied to the entire block that contains the cursor, not just selected inline text.
---
Lists and Indentation
ToolbarCommand | Effect |
|---|---|
OrderedList | Toggle numbered list |
UnorderedList | Toggle bulleted list |
NumberFormatList | Numbered list with style picker (decimal, roman, alpha, …) |
BulletFormatList | Bulleted list with style picker (disc, square, circle, …) |
Indent | Increase indentation / nest list item |
Outdent | Decrease indentation / un-nest list item |
---
Hyperlink Tools
Main toolbar:
ToolbarCommand | Effect |
|---|---|
CreateLink | Open insert-link dialog |
Link quick toolbar — configure via RichTextEditorQuickToolbarSettings.Link:
| Command | Effect |
|---|---|
LinkToolbarCommand.Open | Open the linked URL |
LinkToolbarCommand.Edit | Edit the link href/text |
LinkToolbarCommand.UnLink | Remove hyperlink |
<SfSmartRichTextEditor>
<RichTextEditorQuickToolbarSettings Link="@LinkTools" />
</SfSmartRichTextEditor>
@code {
private List<LinkToolbarItemModel> LinkTools = new()
{
new() { Command = LinkToolbarCommand.Open },
new() { Command = LinkToolbarCommand.Edit },
new() { Command = LinkToolbarCommand.UnLink }
};
}---
Image Quick Toolbar Commands
Configure via RichTextEditorQuickToolbarSettings.Image:
| Command | Effect |
|---|---|
ImageToolbarCommand.Replace | Swap image with another |
ImageToolbarCommand.Align | Align image left / centre / right |
ImageToolbarCommand.Caption | Wrap image in figure/caption |
ImageToolbarCommand.Remove | Delete image from content |
ImageToolbarCommand.OpenImageLink | Follow attached hyperlink |
ImageToolbarCommand.EditImageLink | Edit attached hyperlink |
ImageToolbarCommand.RemoveImageLink | Remove attached hyperlink |
ImageToolbarCommand.Display | Toggle inline / block display |
ImageToolbarCommand.AltText | Edit alternative text |
ImageToolbarCommand.Dimension | Set width/height in px |
<SfSmartRichTextEditor>
<RichTextEditorQuickToolbarSettings Image="@ImageTools" />
</SfSmartRichTextEditor>
@code {
private List<ImageToolbarItemModel> ImageTools = new()
{
new() { Command = ImageToolbarCommand.Replace },
new() { Command = ImageToolbarCommand.Align },
new() { Command = ImageToolbarCommand.Caption },
new() { Command = ImageToolbarCommand.Remove },
new() { Command = ImageToolbarCommand.HorizontalSeparator },
new() { Command = ImageToolbarCommand.AltText },
new() { Command = ImageToolbarCommand.Dimension }
};
}---
Table Quick Toolbar Commands
Configure via RichTextEditorQuickToolbarSettings.Table:
| Command | Effect |
|---|---|
TableToolbarCommand.TableHeader | Toggle table header row |
TableToolbarCommand.TableColumns | Insert/delete column dropdown |
TableToolbarCommand.TableRows | Insert/delete row dropdown |
TableToolbarCommand.TableCell | Merge / split cells |
TableToolbarCommand.TableCellHorizontalAlign | Horizontal cell alignment |
TableToolbarCommand.TableCellVerticalAlign | Vertical cell alignment |
TableToolbarCommand.TableEditProperties | Edit width, padding, spacing |
TableToolbarCommand.RemoveTable | Delete entire table |
---
Utility Tools
ToolbarCommand | Effect |
|---|---|
SourceCode | Toggle HTML source view |
Preview | Show render preview |
FullScreen | Maximise editor to viewport |
Print | Print editor content |
FormatPainter | Copy formatting; double-click for sticky mode |
Undo | Undo last action |
Redo | Redo last undone action |
Separator | Visual divider between toolbar groups |
---
Removing Default Tools
Pass only the tools you want — the default set is replaced entirely:
<SfSmartRichTextEditor>
<RichTextEditorToolbarSettings Items="@MinimalTools" />
</SfSmartRichTextEditor>
@code {
private List<ToolbarItemModel> MinimalTools = new()
{
new() { Command = ToolbarCommand.Bold },
new() { Command = ToolbarCommand.Italic },
new() { Command = ToolbarCommand.Underline },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.Undo },
new() { Command = ToolbarCommand.Redo }
};
}Omitting a tool from Items removes it; you don't need any separate "remove" call.Custom Tools
Table of Contents
---
Custom Toolbar Items
Use RichTextEditorCustomToolbarItems inside RichTextEditorToolbarSettings to add buttons with arbitrary Blazor content (text labels, icons, or full templates). Reference the custom item in Items by its Name:
@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor @ref="SmartRteObj">
<RichTextEditorToolbarSettings Items="@Tools">
<RichTextEditorCustomToolbarItems>
<RichTextEditorCustomToolbarItem Name="Symbol">
<Template>
<SfButton @onclick="InsertSymbol">Ω</SfButton>
</Template>
</RichTextEditorCustomToolbarItem>
</RichTextEditorCustomToolbarItems>
</RichTextEditorToolbarSettings>
<p>Click <b>Ω</b> to insert a special character at the cursor.</p>
</SfSmartRichTextEditor>
@code {
private SfSmartRichTextEditor SmartRteObj = default!;
private List<ToolbarItemModel> Tools = new()
{
new() { Command = ToolbarCommand.Bold },
new() { Command = ToolbarCommand.Italic },
new() { Command = ToolbarCommand.Separator },
new() { Name = "Symbol", TooltipText = "Insert Symbol" }, // custom item
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.SourceCode },
new() { Command = ToolbarCommand.FullScreen }
};
private async Task InsertSymbol()
{
await SmartRteObj.ExecuteCommandAsync(
CommandName.InsertText,
"₹",
new ExecuteCommandOption { Undo = true }); // add to undo stack
}
}Key points:
NameinToolbarItemModelmust matchNameinRichTextEditorCustomToolbarItemTooltipTextsets the accessible tooltip- Blazor components (buttons, dropdowns, etc.) are valid template content
---
ExecuteCommandAsync
SfSmartRichTextEditor.ExecuteCommandAsync applies formatting or inserts content at the current cursor position programmatically.
HTML Editor Commands
| Command | Signature | Description |
|---|---|---|
Bold | ExecuteCommandAsync(CommandName.Bold) | Toggle bold |
Italic | ExecuteCommandAsync(CommandName.Italic) | Toggle italic |
Underline | ExecuteCommandAsync(CommandName.Underline) | Toggle underline |
StrikeThrough | ExecuteCommandAsync(CommandName.StrikeThrough) | Toggle strikethrough |
Superscript | ExecuteCommandAsync(CommandName.Superscript) | Toggle superscript |
Subscript | ExecuteCommandAsync(CommandName.Subscript) | Toggle subscript |
Uppercase | ExecuteCommandAsync(CommandName.Uppercase) | Convert to uppercase |
Lowercase | ExecuteCommandAsync(CommandName.Lowercase) | Convert to lowercase |
FontColor | ExecuteCommandAsync(CommandName.FontColor, "Red") | Set font colour |
FontName | ExecuteCommandAsync(CommandName.FontName, "Impact") | Set font family |
FontSize | ExecuteCommandAsync(CommandName.FontSize, "10pt") | Set font size |
BackgroundColor | ExecuteCommandAsync(CommandName.BackgroundColor, "yellow") | Set highlight colour |
JustifyCenter | ExecuteCommandAsync(CommandName.JustifyCenter) | Centre-align |
JustifyLeft | ExecuteCommandAsync(CommandName.JustifyLeft) | Left-align |
JustifyRight | ExecuteCommandAsync(CommandName.JustifyRight) | Right-align |
JustifyFull | ExecuteCommandAsync(CommandName.JustifyFull) | Justify |
Indent | ExecuteCommandAsync(CommandName.Indent) | Increase indent |
Outdent | ExecuteCommandAsync(CommandName.Outdent) | Decrease indent |
InsertText | ExecuteCommandAsync(CommandName.InsertText, "text") | Insert plain text |
InsertHTML | ExecuteCommandAsync(CommandName.InsertHTML, "<b>hi</b>") | Insert HTML at cursor |
InsertOrderedList | ExecuteCommandAsync(CommandName.InsertOrderedList) | Start numbered list |
InsertUnorderedList | ExecuteCommandAsync(CommandName.InsertUnorderedList) | Start bullet list |
NumberFormatList | ExecuteCommandAsync(CommandName.NumberFormatList, "Decimal") | Styled numbered list |
BulletFormatList | ExecuteCommandAsync(CommandName.BulletFormatList, "Disc") | Styled bullet list |
RemoveFormat | ExecuteCommandAsync(CommandName.RemoveFormat) | Strip all formatting |
CreateLink | ExecuteCommandAsync(CommandName.CreateLink, new LinkCommandsArgs { Text="Link", Url="https://..." }) | Insert hyperlink |
InsertImage | ExecuteCommandAsync(CommandName.InsertImage, new ImageCommandsArgs { Url="...", CssClass="rte-img" }) | Insert image |
Undo | ExecuteCommandAsync(CommandName.Undo) | Undo last action |
Redo | ExecuteCommandAsync(CommandName.Redo) | Redo last undone action |
`ExecuteCommandOption`: Pass new ExecuteCommandOption { Undo = true } to ensure programmatic changes are tracked in the undo stack.
@code {
private async Task ApplyYellow()
{
await SmartRteObj.ExecuteCommandAsync(
CommandName.BackgroundColor,
"yellow",
new ExecuteCommandOption { Undo = true });
}
}---
Slash Commands
Slash commands show a floating suggestion menu when the user types / at the start of a line.
Enabling with Built-in Items
<SfSmartRichTextEditor Placeholder="Type / for commands">
<RichTextEditorSlashMenuSettings Enable="true" />
</SfSmartRichTextEditor>Custom Slash Menu Items
Supply an Items list. Built-in items use SlashMenuCommand; custom items use freeform properties:
<SfSmartRichTextEditor @ref="SmartRteObj" Placeholder="Type '/' and choose format">
<RichTextEditorToolbarSettings Items="@Tools" />
<RichTextEditorEvents SlashMenuItemSelecting="OnSlashSelect" />
<RichTextEditorSlashMenuSettings Enable="true" Items="@SlashItems" />
</SfSmartRichTextEditor>
@code {
private SfSmartRichTextEditor SmartRteObj = default!;
private List<SlashMenuItemModel> SlashItems = new()
{
// Built-in items
new() { Command = SlashMenuCommand.Heading1 },
new() { Command = SlashMenuCommand.Heading2 },
new() { Command = SlashMenuCommand.Paragraph },
new() { Command = SlashMenuCommand.OrderedList },
new() { Command = SlashMenuCommand.UnorderedList },
new() { Command = SlashMenuCommand.Blockquote },
new() { Command = SlashMenuCommand.CodeBlock },
new() { Command = SlashMenuCommand.Table },
new() { Command = SlashMenuCommand.Image },
// Custom items
new() {
Text = "Meeting Notes",
GroupBy = "Custom",
IconCss = "e-icons e-description",
Description = "Insert a meeting note template."
},
new() {
Text = "Signature",
GroupBy = "Custom",
IconCss = "e-icons e-signature",
Description = "Insert a signature block."
}
};
private async Task OnSlashSelect(SlashMenuSelectEventArgs args)
{
string html = args.ItemData.Text switch
{
"Meeting Notes" => "<p><strong>Meeting Notes</strong></p><table>...</table>",
"Signature" => "<p>Warm regards,<br/>John Doe</p>",
_ => string.Empty
};
if (!string.IsNullOrEmpty(html))
await SmartRteObj.ExecuteCommandAsync(CommandName.InsertHTML, html);
}
}`SlashMenuItemModel` properties:
| Property | Description |
|---|---|
Command | Built-in SlashMenuCommand value (built-in items only) |
Text | Display label |
GroupBy | Group header in the menu |
IconCss | CSS class for the icon |
Description | Short description shown below the label |
---
Enabling and Disabling Toolbar Items
Use EnableToolbarItemAsync / DisableToolbarItemAsync to toggle built-in or custom items at runtime:
<SfSmartRichTextEditor @ref="SmartRteObj">
<RichTextEditorToolbarSettings Items="@Tools">
<RichTextEditorCustomToolbarItems>
<RichTextEditorCustomToolbarItem Name="MyTool">
<Template><SfButton>Custom</SfButton></Template>
</RichTextEditorCustomToolbarItem>
</RichTextEditorCustomToolbarItems>
</RichTextEditorToolbarSettings>
</SfSmartRichTextEditor>
@code {
private SfSmartRichTextEditor SmartRteObj = default!;
// Disable Bold and the custom "MyTool" item
private async Task DisableItems()
{
await SmartRteObj.DisableToolbarItemAsync(new List<ToolbarItemModel>
{
new() { Command = ToolbarCommand.Bold },
new() { Name = "MyTool" } // use "Custom" command name for custom items
});
}
private async Task EnableItems()
{
await SmartRteObj.EnableToolbarItemAsync(new List<ToolbarItemModel>
{
new() { Command = ToolbarCommand.Bold },
new() { Name = "MyTool" }
});
}
}For custom toolbar items, set Command = ToolbarCommand.Custom in the model passed to these methods to correctly target them during source-code-view and quick-toolbar operations.Data Binding
Table of Contents
- Two-way Binding with @bind-Value
- One-way Binding with Value
- Retrieving Content Programmatically
- Auto-save
- Character Count and Limits
- Read-only Mode
---
Two-way Binding with @bind-Value
@bind-Value keeps a C# string variable and the editor's HTML content in sync. Changes in the editor update the variable; changes to the variable update the editor:
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor @bind-Value="@Content" />
<!-- Live preview of bound value -->
<textarea rows="5" cols="60" @bind="@Content" />
@code {
private string Content { get; set; } = "<p>Start editing here.</p>";
}Valueacceptsstringtype and holds valid HTML (or Markdown whenEditorMode="Markdown").
---
One-way Binding with Value
Supply an initial HTML string via Value and handle changes with ValueChange when you need more control over when the bound state updates:
<SfSmartRichTextEditor Value="@InitialContent">
<RichTextEditorEvents ValueChange="@OnChange" />
</SfSmartRichTextEditor>
@code {
private string InitialContent = "<p>Default content.</p>";
private void OnChange(Syncfusion.Blazor.RichTextEditor.ChangeEventArgs args)
{
// args.Value holds the current editor HTML
// Save to DB, validate, etc.
InitialContent = args.Value;
}
}ValueChangefires when the editor loses focus or at the configuredSaveInterval. It does not fire on every keystroke — useOnActionCompletefor keystroke-level notifications.
---
Retrieving Content Programmatically
Use the @ref attribute and async API methods to pull content without waiting for a blur:
<SfSmartRichTextEditor @ref="SmartRteObj" @bind-Value="@Content">
<p>Type something here.</p>
</SfSmartRichTextEditor>
<button @onclick="GetContent">Get Content</button>
@code {
private SfSmartRichTextEditor SmartRteObj = default!;
private string Content { get; set; } = string.Empty;
private async Task GetContent()
{
// Plain-text length (excludes HTML tags)
int charCount = await SmartRteObj.GetCharCountAsync();
// Inner text (no tags)
string text = await SmartRteObj.GetTextAsync();
// Full HTML string (same as Value)
string html = Content;
}
}---
Auto-save
Configure periodic or idle-triggered saving with SaveInterval and AutoSaveOnIdle:
| Property | Type | Default | Description |
|---|---|---|---|
SaveInterval | int | 10000 | Interval in ms at which ValueChange fires (or idle timeout when AutoSaveOnIdle is true) |
AutoSaveOnIdle | bool | false | When true, saves after the user stops typing for SaveInterval ms instead of on a fixed timer |
<SfSmartRichTextEditor SaveInterval="5000" AutoSaveOnIdle="true" @bind-Value="@Content">
<RichTextEditorEvents ValueChange="@OnAutoSave" />
<p>Content is saved automatically after 5 s of idle time.</p>
</SfSmartRichTextEditor>
@code {
private string Content { get; set; } = string.Empty;
private async Task OnAutoSave(Syncfusion.Blazor.RichTextEditor.ChangeEventArgs args)
{
Content = args.Value;
await MyService.PersistAsync(Content); // save to DB / local storage
}
}---
Character Count and Limits
Show a live character counter and optionally cap content length:
<SfSmartRichTextEditor ShowCharCount="true" MaxLength="500" @bind-Value="@Content">
<p>This editor limits content to 500 characters.</p>
</SfSmartRichTextEditor>
@code {
private string Content { get; set; } = string.Empty;
}| Property | Type | Default | Description |
|---|---|---|---|
ShowCharCount | bool | false | Displays a character counter in the bottom-right corner |
MaxLength | int | int.MaxValue | Hard cap on character count; typing stops at the limit |
---
Read-only Mode
Set Readonly="true" to display content without allowing edits. The toolbar is hidden automatically. Toggle it at runtime via state:
<SfSmartRichTextEditor Readonly="@IsReadonly" @bind-Value="@Content">
<p>This content is read-only by default.</p>
</SfSmartRichTextEditor>
<button @onclick="() => IsReadonly = !IsReadonly">Toggle Edit</button>
@code {
private bool IsReadonly = true;
private string Content { get; set; } = "<p>Saved content displayed here.</p>";
}In read-only mode the editor renders as a styled HTML container, preserving all formatting. Combine with EnableHtmlSanitizer="true" (the default) to prevent XSS when displaying user-supplied content.Editor Modes
Table of Contents
---
HTML Mode (Default)
EditorMode.HTML renders a contenteditable DIV. All toolbar formatting produces standard HTML tags. This is the default and requires no explicit configuration:
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor EditorMode="EditorMode.HTML">
<p>The Smart Rich Text Editor is a WYSIWYG editor that returns <b>valid HTML</b>.</p>
<ul>
<li>Supports IFRAME and DIV modes</li>
<li>Modular toolbar</li>
<li>Markdown editing</li>
</ul>
</SfSmartRichTextEditor>Value / @bind-Value contains the serialised HTML string. ---
IFrame Mode
IFrame mode renders the editing surface inside a sandboxed <iframe>, isolating its CSS from the host page. Use it when the host application's global styles would interfere with the editor content. IFrame mode is enabled via the <RichTextEditorIFrameSettings Enable="true" /> child component nested inside <SfSmartRichTextEditor>
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor>
<RichTextEditorIFrameSettings Enable="true" />
<p>Editing in an isolated iframe — host-page styles do not bleed in.</p>
</SfSmartRichTextEditor>Customizing IFrame Body Attributes
Pass additional attributes to the iframe body element using Attributes:
<SfSmartRichTextEditor>
<RichTextEditorIFrameSettings Enable="true" Attributes="@IframeAttributes" />
</SfSmartRichTextEditor>
@code {
private Dictionary<string, object> IframeAttributes = new()
{
{ "style", "background: lightgray;" }
};
}Injecting External CSS and Scripts
Inject external stylesheets or scripts into the iframe document using Resources:
<SfSmartRichTextEditor>
<RichTextEditorIFrameSettings Enable="true" Resources="@Resources" />
</SfSmartRichTextEditor>
@code {
private ResourcesModel Resources { get; set; } = new ResourcesModel()
{
Styles = new string[] { "/styles.css" },
Scripts = new string[] { "/script.js" }
};
}TheResourcesModelacceptsStyles(CSS paths) andScripts(JS paths) — both are string arrays resolved relative to the app root. Seeproperties.md → RichTextEditorIFrameSettingsfor the full child-component reference.
---
Markdown Mode
Set EditorMode="EditorMode.Markdown" to switch to Markdown editing. The editor input and Value property use Markdown syntax. A third-party library such as Marked.js must be added to the page to render a live HTML preview. Supported block tags: h1–h6, blockquote, pre, p, ordered list (OL), unordered list (UL) Supported inline tags: Bold, Italic, StrikeThrough, InlineCode, Subscript, Superscript, UpperCase, LowerCase
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor EditorMode="EditorMode.Markdown" @bind-Value="@MarkdownValue">
***Overview*** The Smart Rich Text Editor supports Markdown editing mode.
***Key features***
*Mode*: Provides IFRAME and DIV mode.
*Toolbar*: Provide a fully customizable toolbar.
*Preview*: Preview the modified content before saving it.
</SfSmartRichTextEditor>
@code {
private string MarkdownValue { get; set; } = string.Empty;
}Markdown Toolbar Items
For Markdown mode, use markdown-specific toolbar commands instead of the HTML defaults:
<RichTextEditorToolbarSettings Items="@MdTools" />
@code {
private List<ToolbarItemModel> MdTools = new()
{
new() { Command = ToolbarCommand.Bold },
new() { Command = ToolbarCommand.Italic },
new() { Command = ToolbarCommand.StrikeThrough },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.OrderedList },
new() { Command = ToolbarCommand.UnorderedList },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.Formats },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.Preview }, // live HTML preview
new() { Command = ToolbarCommand.Undo },
new() { Command = ToolbarCommand.Redo }
};
}Displaying a Markdown Preview
Add the Marked library and render the preview on ValueChange:
<!-- wwwroot/index.html or Pages/_Host.cshtml -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor EditorMode="EditorMode.Markdown" @bind-Value="@MarkdownValue">
<RichTextEditorEvents ValueChange="@OnValueChange" />
</SfSmartRichTextEditor>
<div @ref="PreviewDiv"></div>
@code {
private string MarkdownValue { get; set; } = string.Empty;
private ElementReference PreviewDiv;
[Inject] private IJSRuntime JS { get; set; } = default!;
private async Task OnValueChange(Syncfusion.Blazor.RichTextEditor.ChangeEventArgs args)
{
// Render Markdown → HTML using Marked.js
await JS.InvokeVoidAsync("renderMarkdown", PreviewDiv, args.Value);
}
}// wwwroot/app.js
function renderMarkdown(el, markdown) {
el.innerHTML = marked.parse(markdown ?? "");
}---
Source Code / HTML View
Add ToolbarCommand.SourceCode to the toolbar to give users an HTML source editor. This is available in HTML mode only — Markdown mode has a Preview button instead:
<RichTextEditorToolbarSettings Items="@Tools" />
@code {
private List<ToolbarItemModel> Tools = new()
{
new() { Command = ToolbarCommand.Bold },
new() { Command = ToolbarCommand.Italic },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.SourceCode } // toggle HTML source view
};
}Toggling to source code view and back does not lose content. The WYSIWYG surface and source view stay in sync.
Events
Table of Contents
- Wiring Events
- Complete Event Reference
- Lifecycle Events
- Focus & Interaction
- Value & Content
- Toolbar Command Lifecycle
- Dialog Events
- Quick Toolbar Events
- Image Events
- Media Events
- Resize Events
- Toolbar Status Events
- Export Events
- Slash Menu Events
- Common Patterns
---
Wiring Events
All events are registered through the RichTextEditorEvents child component:
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor @bind-Value="@Content">
<RichTextEditorEvents
Created="@OnCreated"
ValueChange="@OnValueChange"
OnActionBegin="@OnActionBegin"
Blur="@OnBlur"
Focus="@OnFocus" />
</SfSmartRichTextEditor>
@code {
private string Content { get; set; } = string.Empty;
private void OnCreated(object args) { /* editor is ready */ }
private void OnValueChange(Syncfusion.Blazor.RichTextEditor.ChangeEventArgs args) { Content = args.Value; }
private void OnActionBegin(ActionBeginEventArgs args) { /* before toolbar command executes */ }
private void OnBlur(BlurEventArgs args) { /* editor lost focus */ }
private void OnFocus(Syncfusion.Blazor.RichTextEditor.FocusEventArgs args) { /* editor gained focus */ }
}---
Complete Event Reference
Lifecycle Events
Created
Fires after the editor renders for the first time. EventArgs: Object — no properties ---
Destroyed
Fires after the component is disposed. EventArgs: DestroyedEventArgs — no properties (marker class) ---
Focus & Interaction
Focus
Fires when the editor gains focus. EventArgs: `Syncfusion.Blazor.RichTextEditor.FocusEventArgs`
| Property | Type | Description |
|---|---|---|
IsInteracted | bool | true if focus was triggered by user interaction |
---
Blur
Fires when the editor loses focus. EventArgs: `BlurEventArgs`
| Property | Type | Description |
|---|---|---|
IsInteracted | bool | true if blur was triggered by user interaction |
---
OnToolbarClick
Fires when a toolbar item is clicked. EventArgs: `ToolbarClickEventArgs`
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to cancel the toolbar click action |
Item | Item? | Data for the clicked toolbar item |
OriginalEvent | object? | The underlying JavaScript event object |
RequestType | string? | Type of operation requested by the toolbar action |
---
SelectionChanged
Fires when the selection range changes (not fired for a collapsed cursor). EventArgs: `SelectionChangedEventArgs`
| Property | Type | Description |
|---|---|---|
EditorMode | EditorMode | HTML or Markdown |
SelectedContent | string? | Full HTML markup of the current non-empty selection |
---
Value & Content
ValueChange
Fires on blur or at SaveInterval. EventArgs: `Syncfusion.Blazor.RichTextEditor.ChangeEventArgs`
| Property | Type | Description |
|---|---|---|
Value | string? | Current HTML content of the editor |
---
BeforePasteCleanup
Fires before pasted content is sanitised. EventArgs: `PasteCleanupArgs`
| Property | Type | Description |
|---|---|---|
Value | string? | The pasted content — modify to transform paste output |
FilesData | List<FileInfo>? | Image file data included in the paste |
---
AfterPasteCleanup
Fires after pasted content is sanitised. EventArgs: `PasteCleanupArgs`
| Property | Type | Description |
|---|---|---|
Value | string? | The cleaned paste content |
FilesData | List<FileInfo>? | Image file data included in the paste |
---
Toolbar Command Lifecycle
OnActionBegin
Fires before a toolbar command executes. EventArgs: `ActionBeginEventArgs`
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to cancel the action |
RequestType | string? | Name of the command being initiated |
ExportValue | string? | Content to export (set during export actions) |
---
OnActionComplete
Fires after a toolbar command completes. EventArgs: `ActionCompleteEventArgs`
| Property | Type | Description |
|---|---|---|
EditorMode | string? | "HTML" or "Markdown" |
RequestType | string? | Name of the completed command |
---
Dialog Events
OnDialogOpen
Fires before a dialog opens (cancellable via args.Cancel). EventArgs: `BeforeOpenEventArgs` (Syncfusion.Blazor.Popups — see Popups API) ---
DialogOpened
Fires after a dialog finishes opening. EventArgs: DialogOpenEventArgs — no properties (marker class) ---
OnDialogClose
Fires before a dialog closes (cancellable via args.Cancel). EventArgs: `BeforeCloseEventArgs` (Syncfusion.Blazor.Popups — see Popups API) ---
DialogClosed
Fires after a dialog has fully closed. EventArgs: `DialogCloseEventArgs`
| Property | Type | Description |
|---|---|---|
IsInteracted | bool | true if the dialog was closed by user action |
---
Quick Toolbar Events
OnQuickToolbarOpen
Fires before the quick toolbar opens. EventArgs: `BeforeQuickToolbarOpenArgs`
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to prevent the quick toolbar from opening |
PositionX | int | Horizontal position (deprecated) |
PositionY | int | Vertical position (deprecated) |
---
QuickToolbarOpened
Fires after the quick toolbar opens. EventArgs: QuickToolbarEventArgs — no properties (marker class) ---
QuickToolbarClosed
Fires after the quick toolbar closes. EventArgs: QuickToolbarEventArgs — no properties (marker class) ---
Image Events
OnImageSelected
Fires when an image is selected or dragged into the insert dialog. EventArgs: `SelectedEventArgs` (Syncfusion.Blazor.Inputs — see Inputs API) ---
BeforeUploadImage
Fires before image upload begins (cancellable). EventArgs: `ImageUploadingEventArgs` (inherits `FileUploadingEventArgs`)
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to cancel the upload |
CurrentRequest | object? | The XMLHttpRequest instance |
CustomFormData | object? | Extra key/value pairs to append to the upload |
FilesData | List<FileInfo>? | Files preparing for upload |
---
OnImageUploadSuccess
Fires when an image is successfully uploaded. EventArgs: `ImageSuccessEventArgs` (inherits `FileUploadSuccessEventArgs`)
| Property | Type | Description |
|---|---|---|
DetectImageSource | ImageInputSource? | How the image arrived: Uploaded, Dropped, or Pasted |
DetectMediaSource | MediaInputSource? | How the media arrived: Uploaded, Dropped, or Pasted |
File | FileInfo? | Uploaded file details |
Operation | string? | Upload operation type |
Response | ResponseEventArgs? | HTTP response information |
StatusText | string? | Status message |
---
OnImageUploadFailed
Fires when an image upload fails. EventArgs: `ImageFailedEventArgs` (inherits `FileUploadFailedEventArgs`)
| Property | Type | Description |
|---|---|---|
File | FileInfo? | Details of the failed file |
Operation | string? | Upload operation type |
Response | ResponseEventArgs? | HTTP response information |
StatusText | string? | Textual description of the failure |
---
ImageUploadChange
Fires when an image is uploaded and inserted into editor content. EventArgs: `ImageUploadChangeEventArgs`
| Property | Type | Description |
|---|---|---|
ImageUrl | string? | Image URL inserted into the editor |
Files | List<UploadFiles>? | List of image files that were uploaded |
---
OnImageRemoving
Fires when an image is removed from the insert dialog. EventArgs: `RemovingEventArgs` (Syncfusion.Blazor.Inputs — see Inputs API) ---
OnImageDrop
Fires when an image is being dropped into editor content (cancellable). EventArgs: `BeforeImageDropEventArgs`
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to block the image drop/insert |
---
ImageDelete
Fires when an image is deleted from editor content. EventArgs: `AfterImageDeleteEventArgs` (inherits `MediaDeletedEventArgs`)
| Property | Type | Description |
|---|---|---|
Src | string? | Source URL of the deleted image |
---
Media Events
FileSelected
Fires when media is selected or dragged into the insert media dialog. EventArgs: `SelectedEventArgs` (Syncfusion.Blazor.Inputs — see Inputs API) ---
FileUploading
Fires when selected media begins uploading to the server. EventArgs: `FileUploadingEventArgs`
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to cancel the upload |
CurrentRequest | object? | The XMLHttpRequest instance |
CustomFormData | object? | Extra key/value pairs to append to the upload |
FilesData | List<FileInfo>? | Files preparing for upload |
---
FileUploadSuccess
Fires when media is successfully uploaded. EventArgs: `FileUploadSuccessEventArgs`
| Property | Type | Description |
|---|---|---|
DetectImageSource | ImageInputSource? | How the image arrived: Uploaded, Dropped, or Pasted |
DetectMediaSource | MediaInputSource? | How the media arrived: Uploaded, Dropped, or Pasted |
File | FileInfo? | Uploaded file details |
Operation | string? | Upload operation type |
Response | ResponseEventArgs? | HTTP response information |
StatusText | string? | Status message |
---
FileUploadFailed
Fires when a media upload fails. EventArgs: `FileUploadFailedEventArgs`
| Property | Type | Description |
|---|---|---|
File | FileInfo? | Details of the failed file |
Operation | string? | Upload operation type |
Response | ResponseEventArgs? | HTTP response information |
StatusText | string? | Textual description of the failure |
---
FileUploadChange
Fires when media is uploaded and inserted into editor content. EventArgs: `FileUploadChangeEventArgs`
| Property | Type | Description |
|---|---|---|
FileUrl | string? | Media URL inserted into the editor |
Files | List<UploadFiles>? | List of media files that were uploaded |
---
FileRemoving
Fires when selected media is removed from the upload location. EventArgs: `RemovingEventArgs` (Syncfusion.Blazor.Inputs — see Inputs API) ---
OnMediaDrop
Fires when media files are dropped into the editor (cancellable). EventArgs: `MediaDropEventArgs` (extends `DragEventArgs` — all standard drag/mouse properties inherited)
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to prevent the drop; default false |
MediaType | string? | "Image", "Video", "Audio", or null |
---
MediaDeleted
Fires when media is deleted from editor content. EventArgs: `MediaDeletedEventArgs`
| Property | Type | Description |
|---|---|---|
Src | string? | Source URL of the deleted media element |
---
Resize Events
OnResizeStart
Fires when image resize begins. EventArgs: `ResizeArgs`
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to cancel the resize |
RequestType | string? | Identifies this as a resize start event |
---
OnResizeStop
Fires when image resize ends. EventArgs: `ResizeArgs`
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to cancel the resize completion |
RequestType | string? | Identifies this as a resize stop event |
---
Toolbar Status Events
UpdatedToolbarStatus
Fires when toolbar item states are updated. EventArgs: `ToolbarStatusEventArgs`
| Property | Type | Description |
|---|---|---|
Html | HtmlStatus? | Active/inactive state of each HTML toolbar item |
Markdown | MarkdownStatus? | Active/inactive state of each Markdown toolbar item |
Redo | bool | true if redo is currently available |
Undo | bool | true if undo is currently available |
---
Export Events
OnExport
Fires before PDF/Word export request is sent. EventArgs: `ExportingEventArgs`
| Property | Type | Description |
|---|---|---|
ExportType | string? | "Pdf" or "Word" |
RequestHeader | Dictionary<string, string>? | Custom HTTP headers (e.g. Authorization) |
CustomFormData | Dictionary<string, string>? | Additional form-data for the request body |
---
OnExportFailure
Fires when PDF/Word export HTTP request fails. EventArgs: `ExportFailureEventArgs`
| Property | Type | Description |
|---|---|---|
ExportType | string? | "Word" or "Pdf" |
Message | string? | Error message, e.g. "HTTP error! Status: 404" |
StatusCode | int | HTTP status code, e.g. 404, 500 |
---
Slash Menu Events
SlashMenuItemSelecting
Fires when a slash command item is selected (cancellable). EventArgs: `SlashMenuSelectEventArgs`
| Property | Type | Description |
|---|---|---|
Cancel | bool | Set true to prevent the slash command from executing |
ItemData | SlashMenuItemModel? | The slash menu item being selected |
---
Common Patterns
Auto-save with ValueChange
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor SaveInterval="3000" AutoSaveOnIdle="true">
<RichTextEditorEvents ValueChange="@SaveToDatabase" />
</SfSmartRichTextEditor>
@code {
private async Task SaveToDatabase(Syncfusion.Blazor.RichTextEditor.ChangeEventArgs args)
{
await MyService.SaveContentAsync(args.Value);
}
}Cancel a Dialog with OnDialogOpen
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor>
<RichTextEditorEvents OnDialogOpen="@PreventImageDialog" />
</SfSmartRichTextEditor>
@code {
private void PreventImageDialog(BeforeOpenEventArgs args)
{
// Cancel image insert dialog when in read-only context
args.Cancel = true;
}
}Delete Image from Server on ImageDelete
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor>
<RichTextEditorEvents ImageDelete="@OnImageDeleted" />
</SfSmartRichTextEditor>
@code {
[Inject] private HttpClient Http { get; set; } = default!;
private async Task OnImageDeleted(AfterImageDeleteEventArgs args)
{
var fileName = Path.GetFileName(args.Src);
await Http.DeleteAsync($"/api/images/{fileName}");
}
}Intercept Toolbar Actions with OnActionBegin
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor>
<RichTextEditorEvents OnActionBegin="@LogAction" />
</SfSmartRichTextEditor>
@code {
private void LogAction(ActionBeginEventArgs args)
{
Console.WriteLine($"Toolbar action: {args.Name}");
}
}Detect Text Selection with SelectionChanged
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor>
<RichTextEditorEvents SelectionChanged="@OnSelection" />
</SfSmartRichTextEditor>
@code {
private void OnSelection(Syncfusion.Blazor.RichTextEditor.SelectionChangedEventArgs args)
{
// args.SelectedHTML contains the HTML of the selected range
}
}---
Event Args Reference
Complete property listing for every event argument class in Syncfusion.Blazor.RichTextEditor.
ActionBeginEventArgs
Used by: OnActionBegin
| Property | Type | Access | Description |
|---|---|---|---|
Cancel | bool | get/set | Set true to cancel the action before it executes |
RequestType | string? | get/set | Name of the command being initiated |
ExportValue | string? | get/set | Content to export during export actions |
ActionCompleteEventArgs
Used by: OnActionComplete
| Property | Type | Access | Description |
|---|---|---|---|
EditorMode | string? | get | "HTML" or "Markdown" |
RequestType | string? | get/set | Name of the completed command |
AfterImageDeleteEventArgs
Used by: ImageDelete — inherits all members from MediaDeletedEventArgs
| Property | Type | Access | Description |
|---|---|---|---|
Src | string? | get/set | Source URL of the deleted image (inherited) |
BeforeImageDropEventArgs
Used by: OnImageDrop
| Property | Type | Access | Description |
|---|---|---|---|
Cancel | bool | get/set | Set true to block the image drop/insert |
BeforeQuickToolbarOpenArgs
Used by: OnQuickToolbarOpen
| Property | Type | Access | Description |
|---|---|---|---|
Cancel | bool | get/set | Set true to prevent the quick toolbar from opening |
PositionX | int | get/set | Horizontal position (deprecated) |
PositionY | int | get/set | Vertical position (deprecated) |
BlurEventArgs
Used by: Blur
| Property | Type | Access | Description |
|---|---|---|---|
IsInteracted | bool | get/set | true if blur was triggered by user interaction |
Syncfusion.Blazor.RichTextEditor.ChangeEventArgs
Used by: ValueChange
| Property | Type | Access | Description |
|---|---|---|---|
Value | string? | get | Updated editor HTML content |
DestroyedEventArgs
Used by: Destroyed — no own properties (marker class).
DialogCloseEventArgs
Used by: DialogClosed
| Property | Type | Access | Description |
|---|---|---|---|
IsInteracted | bool | get | true if the dialog was closed by the user |
DialogOpenEventArgs
Used by: DialogOpened — no own properties (marker class).
ExportFailureEventArgs
Used by: OnExportFailure
| Property | Type | Access | Description |
|---|---|---|---|
ExportType | string? | get | "Word" or "Pdf" |
Message | string? | get/set | Error message, e.g. "HTTP error! Status: 404" |
StatusCode | int | get/set | HTTP status code, e.g. 404, 500; default 0 |
ExportingEventArgs
Used by: OnExport
| Property | Type | Access | Description |
|---|---|---|---|
ExportType | string? | get | "Pdf" or "Word" |
RequestHeader | Dictionary<string, string>? | get/set | Custom HTTP headers for the export request (e.g. Authorization) |
CustomFormData | Dictionary<string, string>? | get/set | Additional form-data key/value pairs for the request body |
FileUploadChangeEventArgs
Used by: FileUploadChange
| Property | Type | Access | Description |
|---|---|---|---|
FileUrl | string? | get/set | Media URL to insert into editor content |
Files | List<UploadFiles>? | get/set | List of media files ready for upload |
FileUploadFailedEventArgs
Used by: FileUploadFailed — base class for ImageFailedEventArgs
| Property | Type | Access | Description |
|---|---|---|---|
File | FileInfo? | get | Details of the failed file |
Operation | string? | get | Upload operation type |
Response | ResponseEventArgs? | get/set | HTTP response information |
StatusText | string? | get/set | Textual description of the failure |
FileUploadSuccessEventArgs
Used by: FileUploadSuccess — base class for ImageSuccessEventArgs
| Property | Type | Access | Description |
|---|---|---|---|
DetectImageSource | ImageInputSource? | get/set | How the image was provided: Uploaded, Dropped, or Pasted |
DetectMediaSource | MediaInputSource? | get/set | How the media was provided: Uploaded, Dropped, or Pasted |
File | FileInfo? | get/set | Uploaded file details |
Operation | string? | get | Upload operation type |
Response | ResponseEventArgs? | get/set | HTTP response information |
StatusText | string? | get | Status message |
FileUploadingEventArgs
Used by: FileUploading — base class for ImageUploadingEventArgs
| Property | Type | Access | Description |
|---|---|---|---|
Cancel | bool | get/set | Set true to cancel the upload |
CurrentRequest | object? | get/set | The XMLHttpRequest instance |
CustomFormData | object? | get/set | Extra key/value pairs to append to the upload request |
FilesData | List<FileInfo>? | get/set | Files preparing for upload |
Syncfusion.Blazor.RichTextEditor.FocusEventArgs
Used by: Focus
| Property | Type | Access | Description |
|---|---|---|---|
IsInteracted | bool | get/set | true if focus was triggered by user interaction |
ImageFailedEventArgs
Used by: OnImageUploadFailed — inherits all properties from FileUploadFailedEventArgs; no own properties.
ImageSuccessEventArgs
Used by: OnImageUploadSuccess — inherits all properties from FileUploadSuccessEventArgs; no own properties.
ImageUploadChangeEventArgs
Used by: ImageUploadChange
| Property | Type | Access | Description |
|---|---|---|---|
ImageUrl | string? | get/set | Image URL to insert into editor content |
Files | List<UploadFiles>? | get/set | List of image files for upload |
ImageUploadingEventArgs
Used by: BeforeUploadImage — inherits all properties from FileUploadingEventArgs; no own properties.
MediaDeletedEventArgs
Used by: MediaDeleted — base class for AfterImageDeleteEventArgs
| Property | Type | Access | Description |
|---|---|---|---|
Src | string? | get/set | Source URL of the deleted media element |
MediaDropEventArgs
Used by: OnMediaDrop — extends DragEventArgs (all standard mouse/drag properties inherited)
| Property | Type | Access | Description |
|---|---|---|---|
Cancel | bool | get/set | Set true to prevent the media drop; default false |
MediaType | string? | get/set | Type of dropped media: "Image", "Video", "Audio", or null |
PasteCleanupArgs
Used by: BeforePasteCleanup and AfterPasteCleanup
| Property | Type | Access | Description |
|---|---|---|---|
Value | string? | get/set | The pasted content (modify to transform paste output) |
FilesData | List<FileInfo>? | get/set | Image file data included in the paste |
QuickToolbarEventArgs
Used by: QuickToolbarOpened, QuickToolbarClosed — no own properties (marker class).
ResizeArgs
Used by: OnResizeStart, OnResizeStop
| Property | Type | Access | Description |
|---|---|---|---|
Cancel | bool | get/set | Set true to cancel the resize action |
RequestType | string? | get/set | Indicates whether this is a resize start or stop event |
SelectionChangedEventArgs
Used by: SelectionChanged
| Property | Type | Access | Description |
|---|---|---|---|
EditorMode | EditorMode | get | HTML or Markdown |
SelectedContent | string? | get | Full HTML markup of the current non-empty selection |
SlashMenuSelectEventArgs
Used by: SlashMenuItemSelecting
| Property | Type | Access | Description |
|---|---|---|---|
Cancel | bool | get/set | Set true to prevent the slash command from executing |
ItemData | SlashMenuItemModel? | get/set | The slash menu item being selected |
ToolbarClickEventArgs
Used by: OnToolbarClick
| Property | Type | Access | Description |
|---|---|---|---|
Cancel | bool | get/set | Set true to cancel the toolbar click action |
Item | Item? | get/set | Data for the clicked toolbar item |
OriginalEvent | object? | get/set | The underlying JavaScript event object |
RequestType | string? | get | Type of operation requested by the toolbar action |
ToolbarStatusEventArgs
Used by: UpdatedToolbarStatus
| Property | Type | Access | Description |
|---|---|---|---|
Html | HtmlStatus? | get/set | Active/inactive status of each HTML toolbar item |
Markdown | MarkdownStatus? | get/set | Active/inactive status of each Markdown toolbar item |
Redo | bool | get/set | true if redo is currently available |
Undo | bool | get/set | true if undo is currently available |
Getting Started with Syncfusion Blazor Smart Rich Text Editor
Table of Contents
- Create a New Blazor App
- NuGet Installation
- Configure AI Service
- Service Registration
- Namespace Imports
- CSS and JS References
- Adding the Component
- Retrieving Content
- Blazor Web App Setup
- Common Setup Issues
---
Create a New Blazor App
Visual Studio
Use Microsoft Templates or the Syncfusion Blazor Extension to create a Blazor Server App.
Visual Studio Code
Create a Blazor Server App via terminal (<kbd>Ctrl</kbd>+<kbd>`</kbd>):
dotnet new blazorserver -o BlazorApp
cd BlazorAppFor Blazor Web App (.NET 8+), ensure you select Server Interactivity when creating the project.
---
NuGet Installation
Install the Smart Rich Text Editor package and a theme:
Visual Studio (Package Manager Console):
Install-Package Syncfusion.Blazor.SmartRichTextEditor
Install-Package Syncfusion.Blazor.Themes.NET CLI (Visual Studio Code):
dotnet add package Syncfusion.Blazor.SmartRichTextEditor
dotnet add package Syncfusion.Blazor.Themes
dotnet restoreUse the same version for both packages to avoid compatibility issues.
---
Configure AI Service
SfSmartRichTextEditor requires an AI backend registered in Program.cs. Three backends are supported out of the box: OpenAI, Azure OpenAI, and Ollama. A custom IChatClient is also supported.
OpenAI
Install additional NuGet packages:
Install-Package Microsoft.Extensions.AI
Install-Package Microsoft.Extensions.AI.OpenAIConfigure in Program.cs:
using Syncfusion.Blazor;
using Syncfusion.Blazor.AI;
using Microsoft.Extensions.AI;
using OpenAI;
builder.Services.AddSyncfusionBlazor();
string openAIApiKey = "YOUR_OPENAI_API_KEY";
string openAIModel = "gpt-4"; // or gpt-3.5-turbo, gpt-4-turbo
OpenAIClient openAIClient = new OpenAIClient(openAIApiKey);
IChatClient chatClient = openAIClient.GetChatClient(openAIModel).AsIChatClient();
builder.Services.AddChatClient(chatClient);
builder.Services.AddSingleton<IChatInferenceService, SyncfusionAIService>();Security: Store your API key in environment variables or User Secrets — never hardcode it in source files.
---
Azure OpenAI
Install additional NuGet packages:
Install-Package Microsoft.Extensions.AI
Install-Package Microsoft.Extensions.AI.OpenAI
Install-Package Azure.AI.OpenAIConfigure in Program.cs:
using Syncfusion.Blazor;
using Syncfusion.Blazor.AI;
using Azure.AI.OpenAI;
using Microsoft.Extensions.AI;
using System.ClientModel;
builder.Services.AddSyncfusionBlazor();
string azureOpenAIKey = "AZURE_OPENAI_KEY";
string azureOpenAIEndpoint = "https://your-resource.openai.azure.com/";
string azureOpenAIModel = "your-deployment-name";
AzureOpenAIClient azureOpenAIClient = new AzureOpenAIClient(
new Uri(azureOpenAIEndpoint),
new ApiKeyCredential(azureOpenAIKey)
);
IChatClient chatClient = azureOpenAIClient.GetChatClient(azureOpenAIModel).AsIChatClient();
builder.Services.AddChatClient(chatClient);
builder.Services.AddSingleton<IChatInferenceService, SyncfusionAIService>();Reading credentials from appsettings.json (recommended):
{
"AzureOpenAI": {
"Key": "your-azure-key",
"Endpoint": "https://your-resource.openai.azure.com/",
"DeploymentName": "your-deployment-name"
}
}string azureOpenAIKey = builder.Configuration["AzureOpenAI:Key"];
string azureOpenAIEndpoint = builder.Configuration["AzureOpenAI:Endpoint"];
string azureOpenAIModel = builder.Configuration["AzureOpenAI:DeploymentName"];---
Ollama (Local / Self-hosted)
Install additional NuGet packages:
Install-Package Microsoft.Extensions.AI
Install-Package OllamaSharpConfigure in Program.cs:
using Syncfusion.Blazor;
using Syncfusion.Blazor.AI;
using Microsoft.Extensions.AI;
using OllamaSharp;
builder.Services.AddSyncfusionBlazor();
string modelName = "mistral"; // any model pulled via `ollama pull <model>`
IChatClient chatClient = new OllamaApiClient("http://localhost:11434", modelName);
builder.Services.AddChatClient(chatClient);
builder.Services.AddSingleton<IChatInferenceService, SyncfusionAIService>();Ollama must be running locally (ollama serve) and the model pulled before starting the app.---
Service Registration
Register the Syncfusion Blazor service in Program.cs before builder.Build():
using Syncfusion.Blazor;
// Blazor Server App
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSyncfusionBlazor();
// ... AI service registration (see above) ...
var app = builder.Build();---
Namespace Imports
Add to _Imports.razor:
@using Syncfusion.Blazor
@using Syncfusion.Blazor.SmartRichTextEditorDo not importSyncfusion.Blazor.RichTextEditorunless you also needSfRichTextEditordirectly.SfSmartRichTextEditoris in theSmartRichTextEditornamespace.
---
CSS and JS References
Blazor Server App (App.razor or _Host.cshtml)
For .NET 8, .NET 9, .NET 10 — ~/Components/App.razor:
<head>
<link href="_content/Syncfusion.Blazor.Themes/tailwind.css" rel="stylesheet" />
</head>
<body>
...
<script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js"
type="text/javascript"></script>
</body>For .NET 6 — ~/Pages/_Layout.cshtml:
<link href="_content/Syncfusion.Blazor.Themes/tailwind.css" rel="stylesheet" />
<script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js"></script>Available themes: tailwind.css | bootstrap5.css | material.css | fluent.css | fabric.css | material-dark.css
---
Adding the Component
Minimal usage
@using Syncfusion.Blazor.SmartRichTextEditor
<SfSmartRichTextEditor />With initial content, two-way binding, and AI assistant
@rendermode InteractiveServer
@using Syncfusion.Blazor.SmartRichTextEditor
<SfSmartRichTextEditor @bind-Value="@Content">
<h2>Welcome to Smart Rich Text Editor</h2>
<p>Select text and use the Smart Action toolbar, or press
<kbd>Alt</kbd>+<kbd>Enter</kbd> to open the AI Query dialog.</p>
<AssistViewSettings Placeholder="Ask AI to rewrite or generate content." />
</SfSmartRichTextEditor>
@code {
private string Content { get; set; } = string.Empty;
}With toolbar configured and AI assistant
@rendermode InteractiveServer
@using Syncfusion.Blazor.SmartRichTextEditor
@using Syncfusion.Blazor.RichTextEditor
<SfSmartRichTextEditor @bind-Value="@Content">
<RichTextEditorToolbarSettings Items="@Tools" />
<AssistViewSettings Placeholder="Ask AI for help." />
</SfSmartRichTextEditor>
@code {
private string Content { get; set; } = string.Empty;
private List<ToolbarItemModel> Tools = new()
{
new() { Command = ToolbarCommand.Bold },
new() { Command = ToolbarCommand.Italic },
new() { Command = ToolbarCommand.Underline },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.Formats },
new() { Command = ToolbarCommand.Alignments },
new() { Command = ToolbarCommand.OrderedList },
new() { Command = ToolbarCommand.UnorderedList },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.CreateLink },
new() { Command = ToolbarCommand.Image },
new() { Command = ToolbarCommand.CreateTable },
new() { Command = ToolbarCommand.Separator },
new() { Command = ToolbarCommand.Undo },
new() { Command = ToolbarCommand.Redo }
};
}With custom AI commands and suggestions
@rendermode InteractiveServer
@using Syncfusion.Blazor.SmartRichTextEditor
<SfSmartRichTextEditor @bind-Value="@Content">
<AssistViewSettings Commands="@MyCommands"
Suggestions="@QuickSuggestions"
Placeholder="How can I help you improve this content?" />
</SfSmartRichTextEditor>
@code {
private string Content { get; set; } = "<p>Start writing here...</p>";
private List<AICommands> MyCommands = new()
{
new AICommands { Text = "Summarize", Prompt = "Summarize this content concisely" },
new AICommands { Text = "Expand", Prompt = "Add more details and examples" },
new AICommands { Text = "Fix Grammar", Prompt = "Fix grammar and spelling errors" },
new AICommands
{
Text = "Change Tone",
Items = new List<AICommands>
{
new AICommands { Text = "Professional", Prompt = "Rewrite in a professional tone" },
new AICommands { Text = "Casual", Prompt = "Rewrite in a casual, friendly tone" },
new AICommands { Text = "Formal", Prompt = "Rewrite in a formal tone" }
}
}
};
private List<string> QuickSuggestions = new()
{
"Make it shorter", "Improve clarity", "Fix grammar", "More formal", "Simplify"
};
}---
Retrieving Content
Get HTML value (property)
The Value property always contains the current HTML:
<SfSmartRichTextEditor @bind-Value="@HtmlContent" />
<p>Current HTML: @HtmlContent</p>
@code {
private string HtmlContent { get; set; } = string.Empty;
}Get plain text (method)
<SfSmartRichTextEditor @ref="SmartRteObj" />
<button @onclick="GetPlainText">Get Text</button>
@code {
private SfSmartRichTextEditor SmartRteObj;
private async Task GetPlainText()
{
string plainText = await SmartRteObj.GetTextAsync();
Console.WriteLine(plainText);
}
}Get character count (method)
<SfSmartRichTextEditor @ref="SmartRteObj" />
<button @onclick="GetCount">Get Count</button>
@code {
private SfSmartRichTextEditor SmartRteObj;
private async Task GetCount()
{
double count = await SmartRteObj.GetCharCountAsync();
Console.WriteLine($"Characters: {count}");
}
}Show character count in UI
<SfSmartRichTextEditor @bind-Value="@Content" ShowCharCount="true" MaxLength="1000">
<AssistViewSettings Placeholder="Ask AI for help." />
</SfSmartRichTextEditor>
@code {
private string Content { get; set; } = string.Empty;
}---
Blazor Web App Setup
For .NET 8+ Blazor Web App projects with InteractiveServer render mode:
`Program.cs`:
using Syncfusion.Blazor;
using Syncfusion.Blazor.AI;
using Microsoft.Extensions.AI;
using OpenAI;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddSyncfusionBlazor();
string openAIApiKey = "YOUR_OPENAI_API_KEY";
string openAIModel = "gpt-4";
OpenAIClient openAIClient = new OpenAIClient(openAIApiKey);
IChatClient chatClient = openAIClient.GetChatClient(openAIModel).AsIChatClient();
builder.Services.AddChatClient(chatClient);
builder.Services.AddSingleton<IChatInferenceService, SyncfusionAIService>();
var app = builder.Build();`~/Components/_Imports.razor`:
@using Syncfusion.Blazor
@using Syncfusion.Blazor.SmartRichTextEditor`~/Components/App.razor`:
<head>
<link href="_content/Syncfusion.Blazor.Themes/tailwind.css" rel="stylesheet" />
</head>
<body>
...
<script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js"
type="text/javascript"></script>
</body>`~/Components/Pages/Home.razor`:
@rendermode InteractiveServer
@using Syncfusion.Blazor.SmartRichTextEditor
<SfSmartRichTextEditor>
<h2>Welcome to Smart Rich Text Editor</h2>
<p>Use the Smart Action toolbar or press <kbd>Alt</kbd>+<kbd>Enter</kbd>
to open the AI Query dialog.</p>
<AssistViewSettings Placeholder="Start typing or use AI assistance..." />
</SfSmartRichTextEditor>The@rendermode InteractiveServerdirective is required on each page (or globally inApp.razor) for the component to be interactive in a Blazor Web App.
---
Common Setup Issues
| Problem | Fix |
|---|---|
| Styles not applied | Verify theme CSS <link> is inside <head>, not <body> |
| Component not rendering | Confirm AddSyncfusionBlazor() is called in Program.cs |
| Scripts not loading | Check syncfusion-blazor.min.js is placed at end of <body> |
| AI not responding | Verify AddChatClient(...) and AddSingleton<IChatInferenceService, SyncfusionAIService>() are both registered |
| AI key errors (401) | Check API key is correct and not expired; use environment variables, not hardcoded strings |
| Not interactive in .NET 8+ Web App | Add @rendermode InteractiveServer to the page or globally in App.razor |
SfSmartRichTextEditor not found | Add @using Syncfusion.Blazor.SmartRichTextEditor to _Imports.razor |
| Ollama not responding | Ensure Ollama is running (ollama serve) and model is pulled (ollama pull mistral) |