Rich Text Editor
A fully-featured WYSIWYG editor built on TipTap/ProseMirror. Supports mentions, slash commands, tables, code blocks, task lists, AI actions, image upload, and Word import — all wired through Blazor parameters.
Installation
dotnet add package Lumeo.Editor
One-time app setup (AddLumeo(), CSS & JS) is covered in the
installation guide.
Usage
@using Lumeo <RichTextEditor />
@tiptap/core, starter-kit, extension-mention,
extension-table, extension-code-block-lowlight, extension-image, etc.) plus
lowlight (MIT) and Mammoth 1.11.0 (BSD-2-Clause) for Word import.
No @tiptap-pro/* packages — the AI actions, drag handle, and bubble menu are all
custom Lumeo code using the free MIT primitives. The AI actions invoke your own LLM via the
OnAiAction callback (OpenAI, Anthropic, Mistral, Ollama — your choice, your bill). Lumeo doesn't
ship credentials and doesn't take a cut.
When to Use
- Content authoring surfaces — blog posts, knowledge-base articles, product descriptions
- Long-form fields that benefit from headings, lists, quotes, links, and tables
- Comment or reply surfaces where users expect bold, italic, mentions, and emoji
- Document editors that need Word import, AI writing assistance, or collaborative slash commands
- Anywhere you currently use a Textarea but want structured HTML output
Minimal — Bold, Italic, Link
Standard (default) — Headings, marks, lists, link, undo/redo
Full — Standard + tables, image, code block, AI menu, Word import
None — Toolbar hidden; bubble menu and keyboard shortcuts still active
@ for users, # for tags, $ for template variables./ on a new line to open the command palette. Built-in commands: Heading 1-3, Bullet list, Numbered list, Task list, Quote, Code block, Table, Image, Divider./image). The OnImageRequested callback returns the final URL; the demo returns a placeholder after a simulated upload delay..docx file.
Conversion runs entirely in your browser via WordImporter (Mammoth ships with the
Lumeo.Editor WASM bundle), so this demo works on static hosting with no server. The default style map handles
English and German Word default styles (Title/Titel, Heading 1-6/Überschrift 1-6, Body Text/Textkörper,
List Paragraph/Listenabsatz, etc.). For server-side conversion with custom callbacks (e.g. uploading
embedded images), set OnWordImportRequested.
Markdown shortcuts work too — try '**bold**' or '# Heading'.
Read-only — content is selectable but not editable
Disabled — dimmed and non-interactive
Plain-text character limit: 500. The editor scrolls internally when content overflows 260 px.
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
| Ctrl / ⌘ + B | Bold |
| Ctrl / ⌘ + I | Italic |
| Ctrl / ⌘ + U | Underline |
| Ctrl / ⌘ + Shift + X | Strikethrough |
| Ctrl / ⌘ + Z | Undo |
| Ctrl / ⌘ + Shift + Z | Redo |
| Ctrl / ⌘ + Alt + 1 – 3 | Heading 1 / 2 / 3 |
| / (on a new line) | Open slash-command palette |
| @ # $ | Open the corresponding trigger dropdown |
| **text** | Bold (markdown shortcut) |
| # text (space) | Heading 1 (markdown shortcut) |
| - or * (space) | Bullet list (markdown shortcut) |
| [ ] (space) | Task list item (markdown shortcut) |
API Reference
RichTextEditor
EditorTrigger
| Property | Type | Default | Description |
|---|---|---|---|
| Char | char | — | The character that activates this trigger (e.g. '@'). |
| ItemSource | Func<string, ValueTask<IReadOnlyList<TriggerItem>>> | — | Async callback called on each keystroke with the partial query; returns matching items. |
| ItemTemplate | RenderFragment<TriggerItem>? | null | Optional custom row renderer for the dropdown list. |
| ChipClass | string? | null | CSS classes applied to the chip/pill inserted into the document when an item is selected. |
TriggerItem
| Property | Type | Default | Description |
|---|---|---|---|
| Id | string | — | Unique identifier stored in the document node's data attribute. |
| Label | string | — | Display name shown in the dropdown and rendered in the chip. |
| Subtitle | string? | null | Secondary text shown below the label in the dropdown row. |
| IconName | string? | null | Lucide icon name (e.g. "User") displayed alongside the label. |
| Payload | object? | null | Arbitrary data passed back to the consumer for custom rendering or server look-ups. |
TriggerDropdown
Floating suggestion list rendered above/below a trigger caret, driven by Items + a selected index. The live editor drives its own equivalent in JS; this Razor primitive exists for consumers who want to render their own trigger UI server-side (e.g. a standalone mention input).
EditorImageRequest
| Property | Type | Description |
|---|---|---|
| FileName | string | Original file name chosen by the user. |
| MimeType | string | MIME type of the selected file (e.g. image/png). |
| Size | long | File size in bytes. |
EditorToolbarPreset
| Value | Description |
|---|---|
| None | No toolbar. Bubble menu and keyboard shortcuts remain available. |
| Minimal | Bold, Italic, Link only. |
| Standard | Headings, basic marks (bold, italic, underline, strikethrough), lists, link, undo/redo. Default value. |
| Full | Standard plus tables, image, code block, AI action menu, and Word import button. |
EditorToolbar
The preset-driven toolbar rendered above the editor surface when Toolbar is not None. Rendered internally by RichTextEditor; each button invokes OnCommand, which the parent forwards to the JS editor.
BubbleMenu
A static (non-floating) bubble-menu primitive consumers can drop into a custom toolbar. The live floating bubble menu is rendered in JS by RichTextEditor itself when EnableBubbleMenu is true; this component exists for building a selection menu out of band.
AiActionMenu
Floating list of AI actions (Improve / Shorten / Expand / ...) wired to the editor's selection. Picking an item fires OnAction with the action record; the consumer returns replacement HTML for the current selection.
WordImporter (server-side)
WordImporter is a static server-side helper in Lumeo.Editor
that converts a .docx stream to clean HTML using Mammoth.NET.
Call it from an API endpoint and return the result to the editor via
SetHtmlAsync.
| Member | Description |
|---|---|
| ToHtmlAsync(stream, options?) | Converts a .docx stream to WordImportResult containing Html and Warnings. |
| DefaultStyleMap | Built-in Mammoth style map covering English and German Word styles (Title, Heading 1-6, Body Text, Quote, etc.). |
| WordImportOptions.StyleMap | Custom style map appended after the default map (so custom rules win). |
| WordImportOptions.ConvertImage | Optional async callback (contentType, stream) => url to upload embedded images rather than base64-inlining them. |
ASP.NET Core endpoint example
// ASP.NET Core controller endpoint
[HttpPost("/api/upload-docx")]
public async Task<IActionResult> ImportDocx(IFormFile file)
{
using var stream = file.OpenReadStream();
var result = await WordImporter.ToHtmlAsync(stream);
return Ok(new { html = result.Html, warnings = result.Warnings });
}
// Optional: custom image upload during import
var options = new WordImportOptions
{
ConvertImage = async (contentType, imageStream) =>
{
var url = await _storage.UploadAsync(contentType, imageStream);
return url;
}
};
var result = await WordImporter.ToHtmlAsync(stream, options);