Documentation
Everything the component exposes: parameters, methods, toolbars, modules and the Blazor Server specifics.
Installation
MudExRichTextEditor targets .NET 8, 9 and 10 and works in Blazor WebAssembly and Blazor Server. MudBlazor is pulled in transitively, but the component also renders in projects that do not use MudBlazor themselves.
dotnet add package MudExRichTextEditor
Then register the using once, in _Imports.razor:
@using MudExRichTextEditor
Everything else — Quill, the stylesheets and every bundled module — is loaded on demand from
_content/MudExRichTextEditor. No CDN, no extra script tag in your host page.
Quick start
@page "/"
<MudExRichTextEdit @bind-Value="_html" Height="320" />
@code {
private string _html = "<p>Hello <b>MudBlazor</b>!</p>";
}
The component derives from the MudBlazor.Extensions form base, so @bind-Value,
Required, Label, Validation and Disabled behave the way they do on
a MudTextField. An empty document reports no value, so Required fires again after the user
deletes all text.
Presets
QuillPresets ships three ready-made combinations of toolbar and modules.
- Minimal — bold, italic, underline, strike. No modules.
- Standard — headings, lists, links and images, plus table, image-resize and compression modules.
- Full — everything above plus colors, indentation, alignment, blockquote, code block, video and the table button.
@using MudExRichTextEditor.Types
<MudExRichTextEdit @bind-Value="_html"
Tools="@QuillPresets.Standard.Tools"
Modules="@QuillPresets.Standard.Modules"
Height="360"
Immediate="true" />
Parameters
The most relevant parameters. Everything inherited from the MudBlazor form base
(Label, Required, Disabled, Class, Style,
Validation, Culture) is available too.
| Parameter | Type | Description |
|---|---|---|
Value | string | SemanticHtml of the document |
ValueHtmlBehavior | GetHtmlBehavior | Which representation Value carries: SemanticHtml (default), InnerHtml, Text or Content (Delta JSON). |
Immediate | bool | Raise ValueChanged on every keystroke instead of on blur. |
Tools | QuillTool[] | Toolbar contents. Defaults to QuillTool.All() plus the file and microphone buttons. |
Modules | IQuillModule[] | Quill modules to load. |
ReadOnly | bool | Locks the document; the toolbar hides unless HideToolbarWhenReadOnly is false. |
HideToolbarWhenReadOnly | bool | Default true, applies to the Snow theme. |
Height | MudExSize<double>? | Editor height; without it the editor grows with its content. |
EnableResize | bool | Lets the user drag the bottom edge to resize. |
Placeholder | string | Placeholder text, localized through the MudBlazor.Extensions localizer. |
Theme | QuillTheme | Snow (toolbar above) or Bubble (floating toolbar). |
DebugLevel | QuillDebugLevel | Quill console verbosity. |
BackgroundColor | MudExColor? | Editor surface color. |
ToolBarBackgroundColor | MudExColor? | Toolbar background color. |
BorderColor | MudExColor? | Border color for editor and toolbar. |
CustomUploadFunc | Func<UploadableFile, Task<string>> | Called for pasted, dropped and attached files; return the URL to embed. |
Files / OnGetFilesFunc | IList<UploadableFile> | Pre-fills the attachment dialog with files you already have. |
ToolbarContent | RenderFragment | Replaces the generated toolbar completely. |
EditorContent | RenderFragment | Seeds the editor with markup instead of Value. |
DefaultToolHandlers | DefaultToolHandler[] | Overrides a built-in Quill handler (for example image) with your own callback. |
UseCultureForSpeechRecognition | bool | Passes the component culture to the speech recognizer. |
Methods
Grab a reference with @ref to call these.
| Method | Description |
|---|---|
GetHtml() | The raw innerHTML Quill produced. |
GetSemanticHTML() | Cleaned-up semantic HTML — this is what Value holds by default. |
GetText() | Plain text without markup. |
GetContent() | The Quill Delta as a JSON string. |
GetValue(GetHtmlBehavior) | Any of the above, chosen at runtime. |
SetHtml(string) | Replaces the document; waits for initialization first. |
InsertHtmlAsync(string) | Pastes markup at the caret. |
InsertImage(string url) | Embeds an image at the caret. |
InsertTableAsync(rows, columns) | Inserts an empty table. |
AttachFilesAsync() | Opens the attachment dialog. |
EnableEditor(bool) | Enables or disables editing without re-rendering. |
LoadContent(string delta) | Loads a Quill Delta JSON document. |
GetModule<T>() | Returns a loaded module instance. |
Toolbar & tools
Without a Tools value the editor renders QuillTool.All() plus a file-attachment and a
microphone button. Pass your own array to control both contents and order — tools are grouped by their
group number, and each group becomes one separator-delimited block.
@using MudExRichTextEditor.Types
<MudExRichTextEdit @bind-Value="_html" Tools="@_tools" />
@code {
private QuillTool[] _tools = [
QuillTools.Header(group: 1),
QuillTools.Font(group: 1), // font family dropdown
QuillTools.Size(group: 1), // font size dropdown
QuillTools.Bold(group: 2),
QuillTools.Italic(group: 2),
QuillTools.Link(group: 3),
QuillTools.Image(group: 3),
];
}
QuillTools is the factory for every built-in button: Bold, Italic,
Underline, Strike, Header, Font, Size,
Color, Background, OrderedList, BulletList,
IndentDecrease, IndentIncrease, Align, Blockquote,
CodeBlock, Link, Image, Video and TableButton.
Fonts and sizes: Quill only renders font names it knows. The defaults are
serif and monospace next to the theme font; to offer more, pass your own list to
QuillTools.Font(fonts: [...]) and add matching .ql-font-<name> CSS rules to your
app stylesheet.
To replace the toolbar markup entirely, use the ToolbarContent render fragment instead.
Custom toolbar buttons
CustomTool renders a MudBlazor icon button and hands you the editor instance on click. Icon, tooltip
and color can be static or computed per render, which is how the microphone button switches between
“record” and “stop”.
@using MudExRichTextEditor.Types
<MudExRichTextEdit @ref="_editor" Tools="@_tools" />
@code {
private MudExRichTextEdit _editor;
private QuillTool[] _tools = QuillTool.All()
.Append(new CustomTool(
onClick: (_, editor) => editor.InsertHtmlAsync("<hr />"),
icon: Icons.Material.Filled.HorizontalRule,
tooltip: "Insert divider",
group: 9))
.ToArray();
}
To override a built-in Quill handler rather than adding a button, use DefaultToolHandlers
with the Quill format name, for example new DefaultToolHandler("image", (editor, args) => ...).
Modules
@using MudExRichTextEditor.Extensibility
<MudExRichTextEdit @bind-Value="_html" Modules="@_modules" />
@code {
private IQuillModule[] _modules = [
new QuillBlotFormatterModule(), // resize images by clicking them
new QuillImageCompressorModule(), // shrink pasted/dropped images
new QuillTableBetterModule(), // tables (needs QuillTools.TableButton())
];
}
QuillBlotFormatterModule— resize handles on images and embeds. Part of the Standard and Full presets.QuillImageCompressorModule— downscales images on paste and drop before they are stored.QuillTableBetterModule— tables with a context menu. AddQuillTools.TableButton()to the toolbar to get the insert button.QuillBetterTableModule— the older table implementation, with MudBlazor palette colors for cell backgrounds.QuillMentionModule<T>— see below.
Write your own by deriving from QuillModule: declare JsFiles and CssFiles,
and return your Quill configuration from OnModuleLoadedAsync.
Mentions
QuillMentionModule<T> is generic over your own item type and takes an async lookup that receives
the trigger character and the current search term.
@using MudExRichTextEditor.Extensibility
<MudExRichTextEdit @bind-Value="_html" Modules="@_modules" />
@code {
private IQuillModule[] _modules;
protected override void OnInitialized() => _modules = [
new QuillMentionModule<string>(
(denotationChar, search) => Task.FromResult(
new[] { "Alice", "Bob", "Carol" }.Where(n => n.Contains(search, StringComparison.OrdinalIgnoreCase))),
'@', '#')
];
}
The module also exposes MentionClicked, MentionHovered,
BeforeMentionSelect and AfterMentionSelect callbacks.
The suggestion list is positioned with quill-mention's fixed strategy, so it lands at the caret
even inside a MudDialog or any scrolled or transformed parent.
Files & uploads
The attachment button opens a MudBlazor upload dialog; paste and drag & drop are handled as well. Without
CustomUploadFunc every file becomes a data URL inside the document, which is convenient for demos and
expensive for real content — point it at your storage instead.
<MudExRichTextEdit @bind-Value="_html" CustomUploadFunc="@UploadAsync" />
@code {
// Return the URL the editor should embed. Without this func the file is
// inlined as a data URL, which bloats the stored HTML.
private async Task<string> UploadAsync(UploadableFile file)
{
await file.EnsureDataLoadedAsync();
var url = await _myStorage.SaveAsync(file.FileName, file.Data, file.ContentType);
return url;
}
}
Use Files or OnGetFilesFunc to pre-populate the dialog, and
OnBeforeDialogOpen / OnDialogClosed to react around it.
Value & HTML behavior
ValueHtmlBehavior decides what the binding writes back.
@using MudExRichTextEditor.Types
<MudExRichTextEdit @bind-Value="_html"
ValueHtmlBehavior="GetHtmlBehavior.SemanticHtml" />
@code {
// Read a different representation on demand, independent of the binding:
private async Task ReadAll()
{
var semantic = await _editor.GetSemanticHTML();
var inner = await _editor.GetHtml();
var text = await _editor.GetText();
var delta = await _editor.GetContent(); // Quill Delta as JSON
}
}
SemanticHtml(default) — Quill's cleaned output, best for storing and re-rendering elsewhere.InnerHtml— the editor DOM verbatim, including Quill's own classes.Text— plain text.Content— the Delta document as JSON; load it back withLoadContent.
Quill keeps an empty document as <p><br></p>. The component treats
markup without text or embeds as empty, so validation and ValueChanged behave correctly when the user
clears the field.
Incoming markup runs through Quill's own converter, which is what keeps
<pre>, <ul>/<li> and nested inline formatting intact.
Anything Quill has no blot for is still dropped — register a custom blot if you need it.
Themes & appearance
@using MudExRichTextEditor.Types
<MudExRichTextEdit @bind-Value="_html"
Theme="QuillTheme.Bubble"
BackgroundColor="MudExColor.Surface"
ToolBarBackgroundColor="MudExColor.Primary"
BorderColor="MudExColor.Secondary"
EnableResize="true"
Height="300" />
Colors accept the full MudExColor range: palette entries, CSS variables and literal values. Read-only
mode hides the toolbar by default:
<MudExRichTextEdit Value="@_html" ReadOnly="true" HideToolbarWhenReadOnly="true" />
Blazor Server
The editor needs an interactive render mode; under a static or prerendered-only mode the container renders but
Quill never initializes. Make sure the MudBlazor providers and blazor.web.js are present:
<!-- App.razor / _Host.cshtml -->
<head>
...
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
</head>
<body>
<MudDialogProvider @rendermode="InteractiveServer" />
<MudSnackbarProvider @rendermode="InteractiveServer" />
<MudPopoverProvider @rendermode="InteractiveServer" />
<Routes @rendermode="InteractiveServer" />
<script src="_framework/blazor.web.js"></script>
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
</body>
If the initial value shows up late, check that the component really is interactive
(@rendermode InteractiveServer) — SetHtml waits for initialization before writing.
Self-hosting & offline
All assets ship inside the package and are served from _content/MudExRichTextEditor: Quill itself,
the themes, the mention module, the image compressor, the blot formatter and — since 9.5.1 — the table module.
Nothing is fetched from a CDN, so the component works behind a proxy, in an air-gapped network, and under a strict
Content-Security-Policy.
FAQ
Chrome warns about preloaded CSS from AuralizeBlazor or Nextended.Blazor
That warning comes from the .NET SDK, not from this component. When your app references any Razor class library
with scoped CSS, the SDK adds a Link: <…bundle.scp.css>; rel="preload" header to your own
{App}.styles.css. Chrome logs a warning whenever such a preload is not consumed quickly enough. It is
cosmetic — nothing is broken and nothing is loaded twice.
Can I use it without MudBlazor?
Yes. The package brings its own MudBlazor dependency; you do not have to build the rest of your app with it.
How do I get true HTML instead of Quill markup?
Use the default GetHtmlBehavior.SemanticHtml, or call GetSemanticHTML().
Why does my markup come back changed?
Markup you assign to Value is parsed by Quill, so it is normalized to what Quill can actually
represent: <b> becomes <strong>, <pre> becomes a code block,
list items get Quill's own attributes. The semantic HTML you read back is equivalent, not byte-identical.
Drag & drop and paste
The component handles both itself and inserts the file exactly once, at the drop position. Do not add your own
drop or paste handler on the editor root for files — that is what causes duplicate
images.