# Rich Text Editor

Source: https://lumeo.nativ.sh/components/rich-text-editor

# 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

.NET CLI PackageReference Lumeo CLI

dotnet add package Lumeo.Editor

One-time app setup (`AddLumeo()`, CSS & JS) is covered in the [installation guide](docs/introduction).

## Usage

@using Lumeo

<RichTextEditor />

**In active development.** The RichTextEditor is functional but still being polished — expect rough edges, occasional input lag, and ongoing improvements to the slash/mention dropdowns, Word import fidelity, and AI action wiring. Please report issues on [GitHub](https://github.com/Brain2k-0005/Lumeo/issues).

**Dependencies & licensing — fully MIT, no paid extensions.** Built on TipTap's free MIT extensions (`@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

Preview Code

Basic

Preview Code

Toolbar presets

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

Preview Code

@-mentions

Preview Code

Multiple triggers (@, #, $)

Type `@` for users, `#` for tags, `$` for template variables.

Preview Code

Slash command

Type `/` 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.

Preview Code

Tables, code, and task lists

Preview Code

Image upload

Click the image button in the toolbar (or type `/image`). The `OnImageRequested` callback returns the final URL; the demo returns a placeholder after a simulated upload delay.

Preview Code

AI actions

Select some text in the editor below to see the bubble menu's AI button. Actions: Improve, Shorten, Expand, Fix Grammar, Summarize, Translate.

Preview Code

Word (.docx) import

Click the _Import_ button in the toolbar and pick any `.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`.

Preview Code

With FormField validation

Description\*

Markdown shortcuts work too — try '\*\*bold\*\*' or '# Heading'.

Validate Reset

Preview Code

Read-only and disabled

Read-only — content is selectable but not editable

Disabled — dimmed and non-interactive

Preview Code

Max length + bounded height

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

Property

Type

Default

Description

Value

string?

null

Current HTML content. Two-way bindable via `@bind-Value`.

ValueChanged

EventCallback<string?>

—

Fired on every document change. Carries the serialised HTML.

Placeholder

string

"Start writing…"

Placeholder shown when the editor is empty.

Toolbar

EditorToolbarPreset

Standard

Toolbar density. `None` hides it; `Minimal` = Bold/Italic/Link; `Standard` = headings + marks + lists + undo/redo; `Full` adds tables, image, code block, AI menu, Word import.

MinHeight

int

180

Minimum editor height in pixels.

MaxHeight

int?

null

Optional maximum height in pixels. When set, the content area scrolls internally beyond this height.

Disabled

bool

false

Disables editing and dims the toolbar.

ReadOnly

bool

false

Prevents edits but keeps content selectable (no dimming).

Required

bool

false

Marks the field as required; sets `aria-required` on the root element.

Invalid

bool

false

Shows a destructive ring and sets `aria-invalid`. Also driven automatically when nested inside a `<FormField>` with an error.

ErrorText

string?

null

Error message rendered below the editor when `Invalid` is true (only when not inside a FormField).

HelperText

string?

null

Helper text rendered below the editor when there is no error (only when not inside a FormField).

Label

string?

null

Inline label rendered above the editor (only when not inside a FormField).

Name

string?

null

HTML name attribute, useful for form identification.

Triggers

IReadOnlyList<EditorTrigger>?

null

One or more trigger characters (e.g. `@`, `#`, `$`). Each trigger provides an async `ItemSource` callback.

EnableSlashCommand

bool

true

Enables the built-in `/` command palette (Notion-style). Supply a custom `/` trigger to override the default commands.

EnableTables

bool

true

Enables the TipTap Table extension.

EnableCodeBlock

bool

true

Enables syntax-highlighted code blocks.

EnableImages

bool

true

Enables image upload/paste. Falls back to base64 when `OnImageRequested` is null.

EnableTaskList

bool

true

Enables checkable task-list items.

EnableMarkdownShortcuts

bool

true

Enables Markdown input shortcuts (e.g. `**bold**`, `# Heading`).

EnableAiActions

bool

false

Shows an AI button in the bubble menu when text is selected. Requires `OnAiAction` to be wired.

EnableBubbleMenu

bool

true

Shows the floating bubble menu (Bold, Italic, Link, etc.) when text is selected.

EnableDragHandle

bool

true

Shows the drag handle on the left of each block node for drag-and-drop reordering.

MaxLength

int?

null

Optional plain-text character limit enforced by the editor.

AllowWordImport

bool

false

Adds an _Import .docx_ button to the Full toolbar. By default, conversion runs in-browser via `WordImporter`. Override with `OnWordImportRequested` for server-side conversion.

OnImageRequested

Func<EditorImageRequest, ValueTask<string?>>?

null

Async callback that receives file metadata and returns the final image URL. When null, images are inlined as base64.

OnAiAction

Func<string, string, ValueTask<string?>>?

null

Async callback receiving `(actionId, selectedText)`; returns replacement HTML. Action IDs: `improve`, `shorten`, `expand`, `fix-grammar`, `summarize`, `translate`.

OnWordImportRequested

Func<WordImportPayload, ValueTask<string>>?

null

Optional override. Receives the picked file (filename + bytes) and returns the HTML to insert. When not set, the editor calls `WordImporter.ToHtmlAsync` in-browser and inserts the result.

ToolbarMode

RichTextToolbarMode?

null

Legacy alias for `Toolbar`. Values: None, Basic, Full. Use `Toolbar` (EditorToolbarPreset) for new code.

MaxWordImportBytes

long

52428800

Maximum file size (bytes) allowed for Word import. Default is 50 MB.

FormField

FormFieldContext?

null

Cascaded context from a parent FormField; drives Invalid, Required, and error display automatically.

Class

string?

null

Additional CSS classes applied to the root wrapper element.

AdditionalAttributes

Dictionary<string, object>?

null

Splatted onto the root element. Useful for `data-*` or ARIA attributes.

### 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.

### 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.

### 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);

## Related Components

-   [Textarea](/components/textarea) — Plain multi-line text input without formatting
-   [FormField](/components/form-field) — Wraps any input with a label, help text, and validation error
-   [Form](/components/form) — Full form wrapper with model validation
-   [Input](/components/input) — Single-line text input
