Accent color
# RichTextEditor
## Description
RichTextEditor is a native WYSIWYG text editor. Component state and the public API live in C#; browser editing operations (contenteditable events, formatting commands, and selection management) are handled in the JS/TypeScript bridge.
## Parameters
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Classes | `BitRichTextEditorClassStyles?` | null | Custom CSS classes for different parts of the rich text editor. |
| DebounceMs | `int` | 200 | Debounce window (ms) for content-change notifications while typing. |
| FontFamilies | `IReadOnlyList<string>?` | null | Font families offered in the font-family selector. Null/empty uses defaults. |
| FontSizes | `IReadOnlyList<string>?` | null | Font sizes offered in the font-size selector. Null/empty uses defaults. |
| Height | `string` | 300px | Minimum height of the editing surface (any CSS length). |
| KeyboardShortcuts | `IReadOnlyDictionary<string, string>?` | null | Custom key-combo to command map, merged over the built-in defaults. |
| Localizer | `IBitRichTextEditorLocalizer?` | null | Localized labels/tooltips provider. Null uses built-in English labels. |
| MaxLength | `int?` | null | Maximum plain-text character count. Null means unlimited. |
| OnBlur | `EventCallback` | | Callback for when the editor loses focus. |
| OnChange | `EventCallback<string?>` | | Callback for when the editor content changes. |
| OnError | `EventCallback<BitRichTextEditorError>` | | Callback for when the editor encounters a recoverable error. |
| OnFocus | `EventCallback` | | Callback for when the editor gains focus. |
| OnImageUpload | `Func<BitRichTextEditorImageUpload, Task<string?>>?` | null | Invoked to persist an image binary, returning the URL to embed. When null, dropped or pasted images are embedded as inline data URLs. |
| PasteAsPlainText | `bool` | false | When true, pasted content is inserted as plain text. |
| Placeholder | `string?` | null | The placeholder value of the editor shown while it is empty. |
| ReadOnly | `bool` | false | Makes the editor readonly. |
| SanitizationPolicy | `BitRichTextEditorSanitizationPolicy?` | null | Allowlist policy applied to all content. When null a secure default allowlist is applied. |
| ShowCount | `bool` | false | Show the character/word count footer. |
| ShowToolbar | `bool` | true | Whether the formatting toolbar is shown. |
| Styles | `BitRichTextEditorClassStyles?` | null | Custom CSS styles for different parts of the rich text editor. |
| Toolbar | `BitRichTextEditorToolbar` | BitRichTextEditorToolbar.All | Which toolbar groups to display. |
| ToolbarConfig | `BitRichTextEditorToolbarConfig?` | null | Custom toolbar items and ordering. Null uses the default group order. |
| Value | `string?` | null | The two-way bound HTML content of the editor. |
| AriaLabel | `string?` | null | Gets or sets the accessible label for the component, used by assistive technologies. |
| Class | `string?` | null | Gets or sets the CSS class name(s) to apply to the rendered element. |
| Dir | `BitDir?` | null | Gets or sets the text directionality for the component's content. |
| ForceAnimation | `bool` | false | Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested. |
| HtmlAttributes | `Dictionary<string, object>` | new Dictionary<string, object>() | Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. |
| Id | `string?` | null | Gets or sets the unique identifier for the component's root element. |
| IsEnabled | `bool` | true | Gets or sets a value indicating whether the component is enabled and can respond to user interaction. |
| Style | `string?` | null | Gets or sets the CSS style string to apply to the rendered element. |
| TabIndex | `string?` | null | Gets or sets the tab order index for the component when navigating with the keyboard. |
| Visibility | `BitVisibility` | BitVisibility.Visible | Gets or sets the visibility state (visible, hidden, or collapsed) of the component. |
## Public Members
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| FocusAsync | `ValueTask` | | Moves keyboard focus into the editor. |
| GetHtmlAsync | `ValueTask<string>` | | Returns the current HTML content of the editor. |
| GetTextAsync | `ValueTask<string>` | | Returns the current content of the editor as plain text, with block boundaries rendered as newlines and all markup removed. |
| ExecuteCommandAsync | `Task` | | Runs a raw editing command against the editor. |
| UniqueId | `Guid` | Guid.NewGuid() | Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed. |
| RootElement | `ElementReference` | | Gets the reference to the root HTML element associated with this component. |
## Enums
### BitRichTextEditorToolbar Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| None | 0 | |
| History | 1 | |
| BlockFormat | 2 | |
| Inline | 4 | |
| Lists | 8 | |
| Blocks | 16 | |
| Link | 32 | |
| Alignment | 64 | |
| Clear | 128 | |
| Image | 256 | |
| Color | 512 | |
| Font | 1024 | |
| Indent | 2048 | |
| Script | 4096 | |
| Source | 8192 | |
| Table | 16384 | |
| Media | 32768 | |
| Rule | 65536 | |
| Emoji | 131072 | |
| Find | 262144 | |
| FullScreen | 524288 | |
| Direction | 1048576 | |
| All | 255 | |
| AllExtended | 2097151 | |
### BitVisibility Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Visible | 0 | The content of the component is visible. |
| Hidden | 1 | The content of the component is hidden, but the space it takes on the page remains (visibility:hidden). |
| Collapsed | 2 | The component is hidden (display:none). |
### BitDir Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Ltr | 0 | Ltr (left to right) is to be used for languages that are written from the left to the right (like English). |
| Rtl | 1 | Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic). |
| Auto | 2 | Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element. |
## Sub Classes
### BitRichTextEditorClassStyles Properties
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Root | `string?` | null | Custom CSS classes/styles for the root of the BitRichTextEditor. |
| Toolbar | `string?` | null | Custom CSS classes/styles for the toolbar of the BitRichTextEditor. |
| Group | `string?` | null | Custom CSS classes/styles for the toolbar groups of the BitRichTextEditor. |
| Button | `string?` | null | Custom CSS classes/styles for the toolbar buttons of the BitRichTextEditor. |
| Editor | `string?` | null | Custom CSS classes/styles for the editor (content) area of the BitRichTextEditor. |
| Source | `string?` | null | Custom CSS classes/styles for the HTML source view textarea of the BitRichTextEditor. |
| Count | `string?` | null | Custom CSS classes/styles for the character/word count footer of the BitRichTextEditor. |
### BitRichTextEditorToolbarConfig Properties
Configures toolbar ordering and custom items.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Order | `IReadOnlyList<string>?` | null | Explicit ordering of toolbar entry ids (built-in group ids and custom item ids). |
| CustomItems | `IReadOnlyList<BitRichTextEditorToolbarItem>?` | null | Custom toolbar items (max 50 are rendered). |
### BitRichTextEditorToolbarItem Properties
A custom toolbar button supplied by the host.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Id | `string` | | Unique id used for ordering and lookup. |
| Label | `string?` | null | Text label shown when no icon is provided. |
| Icon | `RenderFragment?` | null | Optional icon content. |
| AriaLabel | `string?` | null | Optional accessible label / tooltip. When omitted, Label is used as the accessible name. |
| OnActivate | `Func<BitRichTextEditor, Task>` | | Action invoked when the item is activated; receives the editor instance. |
### BitRichTextEditorImageUpload Properties
An image to be persisted by the host's OnImageUpload delegate.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| FileName | `string` | | Original file name, when available. |
| ContentType | `string` | | MIME type, e.g. "image/png". |
| Content | `byte[]` | | Raw image bytes. |
### BitRichTextEditorError Properties
An error surfaced by the editor (e.g. invalid URL, failed upload, invalid HTML).
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Code | `string` | | Stable error code, e.g. "invalid-url". |
| Message | `string` | | Human-readable description. |
## Examples
\n**Basic**:
```razor
```
\n**Placeholder & height**:
```razor
```
\n**Readonly**:
```razor
```
\n**Two-way binding**:
```razor
Set content
Clear
Append
```
\n**Focus & blur events**:
```razor
```
\n**Indentation & scripts**:
```razor
```
\n**Toolbar groups**:
```razor
```
\n**Full toolbar**:
```razor
```
\n**Links**:
```razor
```
```csharp
private string? linkHtml = "
```
```csharp
private async Task HandleImageUpload(BitRichTextEditorImageUpload image)
{
// image.FileName, image.ContentType, image.Content (byte[])
var url = await storage.SaveAsync(image.FileName, image.Content);
return url; // return null to cancel the insert
}
```
\n**Colors**:
```razor
```
\n**Fonts**:
```razor
```
```csharp
private readonly string[] fonts = ["Segoe UI", "Georgia", "Courier New", "Comic Sans MS"];
private readonly string[] sizes = ["12px", "16px", "20px", "28px"];
```
\n**Tables**:
```razor
```
\n**Media & rules**:
```razor
```
\n**Source view**:
```razor
```
\n**Sanitization**:
```razor
```
```csharp
private readonly BitRichTextEditorSanitizationPolicy sanitizationPolicy = new()
{
AllowedTags = new HashSet(StringComparer.OrdinalIgnoreCase)
{ "p", "br", "strong", "em", "a", "ul", "ol", "li" },
AllowedAttributes = new Dictionary>(StringComparer.OrdinalIgnoreCase)
{
["*"] = new HashSet(StringComparer.OrdinalIgnoreCase) { "class" },
["a"] = new HashSet(StringComparer.OrdinalIgnoreCase) { "href", "title" },
},
AllowedUriSchemes = new HashSet(StringComparer.OrdinalIgnoreCase)
{ "http", "https", "mailto" },
AllowDataImageUris = false,
};
```
\n**Plain-text paste**:
```razor
```
\n**Find & replace**:
```razor
```
\n**Full screen**:
```razor
```
\n**Slash menu**:
```razor
```
\n**Keyboard shortcuts**:
```razor
```
```csharp
private readonly Dictionary shortcuts = new()
{
["ctrl+shift+s"] = "strikeThrough",
["ctrl+shift+l"] = "insertUnorderedList",
};
```
\n**Emoji**:
```razor
```
\n**Character & word count**:
```razor
```
\n**EditForm validation**:
```razor
Submit
```
```csharp
private readonly FormModel formModel = new();
private bool formSubmitted;
private void HandleValidSubmit() => formSubmitted = true;
public class FormModel : System.ComponentModel.DataAnnotations.IValidatableObject
{
[System.ComponentModel.DataAnnotations.Required(ErrorMessage = "The body is required.")]
public string? Body { get; set; }
public System.Collections.Generic.IEnumerable Validate(System.ComponentModel.DataAnnotations.ValidationContext validationContext)
{
// Body is HTML, so validate the normalized visible text: strip tags, decode entities,
// and trim. Markup with no visible text passes [Required] (the raw HTML is non-empty),
// so require non-whitespace visible text and base the min-length check on it too.
var stripped = System.Text.RegularExpressions.Regex.Replace(Body ?? "", "<[^>]+>", "");
var text = System.Net.WebUtility.HtmlDecode(stripped).Trim();
if (string.IsNullOrWhiteSpace(Body) is false && text.Length == 0)
yield return new System.ComponentModel.DataAnnotations.ValidationResult("The body is required.", [nameof(Body)]);
else if (text.Length > 0 && text.Length < 20)
yield return new System.ComponentModel.DataAnnotations.ValidationResult("Add a bit more detail (min 20 characters).", [nameof(Body)]);
}
}
```
\n**Custom toolbar item**:
```razor
```
```csharp
private readonly BitRichTextEditorToolbarConfig customConfig = new()
{
CustomItems =
[
new()
{
Id = "insert-date",
Label = "Today",
AriaLabel = "Insert today's date",
OnActivate = editor => editor.ExecuteCommandAsync("insertText", DateTime.Now.ToString("yyyy-MM-dd"))
}
]
};
```
\n**Reordering toolbar groups**:
```razor
```
```csharp
// listed ids appear first; enabled-but-omitted groups follow in default order
private readonly BitRichTextEditorToolbarConfig reorderConfig = new()
{
Order = ["inline", "lists", "link"]
};
```
\n**Imperative API**:
```razor
FocusAsync
ExecuteCommand("bold")
GetHtmlAsync
GetTextAsync
```
@bindingHtml``` ```csharp private string? bindingHtml = "
The bound value is just a string you own.
"; ``` \n**Debounce**: ```razorEditor is currently: @focusState
```
```csharp
private string focusState = "blurred";
```
\n**Formatting**:
```razor
Read the docs.
"; private string? linkError; private void HandleLinkHtmlChanged(string? value) { linkHtml = value; linkError = null; // a successful update clears the stale error } ``` \n**Images**: ```razor@apiResult``` ```csharp private BitRichTextEditor apiEditor = default!; private string? apiResult; private async Task FocusEditor() { await apiEditor.FocusAsync(); } private async Task GetEditorHtml() { apiResult = await apiEditor.GetHtmlAsync(); } private async Task GetEditorText() { apiResult = await apiEditor.GetTextAsync(); } ``` \n**Style & Class**: ```razor