# 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
@bindingHtml
``` ```csharp private string? bindingHtml = "

The bound value is just a string you own.

"; ``` \n**Debounce**: ```razor ``` \n**Focus & blur events**: ```razor
Editor is currently: @focusState
``` ```csharp private string focusState = "blurred"; ``` \n**Formatting**: ```razor ``` \n**Indentation & scripts**: ```razor ``` \n**Toolbar groups**: ```razor ``` \n**Full toolbar**: ```razor ``` \n**Links**: ```razor ``` ```csharp private string? linkHtml = "

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 ``` ```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
@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 ```